<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom"><id>https://mtsknn.fi/blog/</id><title>Matias Kinnunen – Blog</title><subtitle>A collection of my wildest adventures with computers. Mostly about web development.</subtitle><link href="https://mtsknn.fi/blog/" /><link href="https://mtsknn.fi/feeds/blog.xml" rel="self" /><updated>2024-10-15T12:00:00+03:00</updated><author><name>Matias Kinnunen</name></author><entry><id>https://mtsknn.fi/blog/indenting-ordered-lists-in-markdown/</id><title>Better way to indent ordered lists in Markdown</title><link href="https://mtsknn.fi/blog/indenting-ordered-lists-in-markdown/" /><published>2024-10-15T12:00:00+03:00</published><updated>2024-10-15T12:00:00+03:00</updated><category term="Markdown"></category><content type="html">&lt;p&gt;&lt;code&gt;1. foo&lt;/code&gt; is annoying because the list item's text is indented with three spaces.
Solution: add another space after the period.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt; Using &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; spaces of indentation.
&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt; ...
&lt;span class=&quot;token list punctuation&quot;&gt;3.&lt;/span&gt; Code blocks are &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;especially annoying&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;:
   ```js
   // &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; spaces of indentation, yuck
   function foo() {
     // &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; spaces of indentation, yuck
     alert('lolz')
   }
   ```
&lt;span class=&quot;token list punctuation&quot;&gt;4.&lt;/span&gt; ...
&lt;span class=&quot;token list punctuation&quot;&gt;5.&lt;/span&gt; And when there are lots of list items:
&lt;span class=&quot;token list punctuation&quot;&gt;6.&lt;/span&gt; ...
&lt;span class=&quot;token list punctuation&quot;&gt;7.&lt;/span&gt; ...
&lt;span class=&quot;token list punctuation&quot;&gt;8.&lt;/span&gt; ...
&lt;span class=&quot;token list punctuation&quot;&gt;9.&lt;/span&gt; ...
&lt;span class=&quot;token list punctuation&quot;&gt;10.&lt;/span&gt; ...the indentation &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;changes to 4 spaces&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; (nice but inconsistent)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt;  Using &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; spaces of indentation.
&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt;  ...
&lt;span class=&quot;token list punctuation&quot;&gt;3.&lt;/span&gt;  Code blocks are &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;now ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;:
    ```js
    // &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; spaces of indentation, sweet
    function foo() {
      // &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; spaces of indentation, sweet
      alert('lolz')
    }
    ```
&lt;span class=&quot;token list punctuation&quot;&gt;4.&lt;/span&gt;  ...
&lt;span class=&quot;token list punctuation&quot;&gt;5.&lt;/span&gt;  And when there are lots of list items:
&lt;span class=&quot;token list punctuation&quot;&gt;6.&lt;/span&gt;  ...
&lt;span class=&quot;token list punctuation&quot;&gt;7.&lt;/span&gt;  ...
&lt;span class=&quot;token list punctuation&quot;&gt;8.&lt;/span&gt;  ...
&lt;span class=&quot;token list punctuation&quot;&gt;9.&lt;/span&gt;  ...
&lt;span class=&quot;token list punctuation&quot;&gt;10.&lt;/span&gt; ...the indentation &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;is still consistently 4 spaces&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;, yay!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This kind of indentation is also &lt;a href=&quot;https://prettier.io/&quot; class=&quot;link link-external&quot;&gt;Prettier&lt;/a&gt;-compatible, nice!
Maybe it should even be the default indentation style.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I noticed this accidentally when writing an answer on Stack Overflow,
where the textarea formats ordered lists like this:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Notice the leading spaces:

 &lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt; foo
 &lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt; bar
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I copy-pasted that to VS Code,
then formatted the file in VS Code (using Prettier),
and Prettier formatted the list like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt;  foo
&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt;  bar
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A-ha!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/github-html-preview-bookmarklet/</id><title>Previewing HTML files directly on GitHub with a bookmarklet</title><link href="https://mtsknn.fi/blog/github-html-preview-bookmarklet/" /><published>2024-10-14T12:00:00+03:00</published><updated>2024-10-14T12:00:00+03:00</updated><category term="Bookmarklets"></category><category term="JavaScript"></category><content type="html">&lt;p&gt;There's no built-in way to preview HTML files on GitHub,
but you can use this nifty bookmarklet.
(GitHub's project managers HATE it!)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a bookmark with this &amp;quot;URL&amp;quot;:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;javascript&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 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; selector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'#read-only-cursor-text-area'&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; html &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;html&lt;span class=&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 function&quot;&gt;alert&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;Error: element &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;selector&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; not found&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;

  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&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;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;html&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open an HTML file on GitHub.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the bookmarklet by &amp;quot;opening&amp;quot; the bookmark.
It replaces the current page's contents with the HTML file's contents.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Works great with self-contained / zero-dependency HTML files generated with &lt;a href=&quot;https://github.com/gildas-lormeau/SingleFile&quot; class=&quot;link link-external&quot;&gt;SingleFile&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The bookmarklet breaks GitHub's client-side routing,
so navigating back with the browser's Back button doesn't work.
Reloading the page (&lt;kbd&gt;F5&lt;/kbd&gt;) fixes the issue.&lt;/li&gt;
&lt;li&gt;The bookmarklet doesn't work on raw.githubusercontent.com
because of a strict &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&quot; class=&quot;link link-external&quot;&gt;Content Security Policy (CSP)&lt;/a&gt;.
(Plus the bookmarklet is looking for an element that's not present on this domain.)&lt;/li&gt;
&lt;li&gt;The CSP used on github.com can also be too strict;
in such cases, I would personally try an &lt;a href=&quot;https://stackoverflow.com/a/37912931/1079869&quot; class=&quot;link link-external&quot;&gt;alternative solution on Stack Overflow by ostrokach&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The bookmarklet is brittle,
i.e. it might need tweaking from time to time as GitHub gets updated.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Alternative bookmarklet code that retains the page's header and footer,
so that running the bookmarklet doesn't break client-side routing:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;javascript&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 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; selector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'#read-only-cursor-text-area'&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; html &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;html&lt;span class=&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 function&quot;&gt;alert&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;Error: element &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;selector&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; not found&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 keyword&quot;&gt;const&lt;/span&gt; $iframe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'iframe'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  $iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'100vh'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  $iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'100%'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  $iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;srcdoc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; html&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'turbo-frame'&lt;/span&gt;&lt;span class=&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;replaceChildren&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$iframe&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  $iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scrollIntoView&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The CSP on github.com blocks the iframe from loading most links,
so with this version most links are effectively disabled
(i.e. clicking a link doesn't do anything, at least on Firefox).
In my case this is a feature, not a bug.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There are (at least) two relevant questions on Stack Overflow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/8446218/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;How to see an HTML page on GitHub as a normal rendered HTML page to see preview in browser, without downloading?&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/6551446/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Can I run HTML files directly from GitHub, instead of just viewing their source?&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neither question has as nice solutions as this one by me (until now).
Bookmarklets are underrated!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/beware-implicit-values/</id><title>Beware implicit `Content-Type: &quot;application/json&quot;`</title><link href="https://mtsknn.fi/blog/beware-implicit-values/" /><published>2024-08-31T12:00:00+03:00</published><updated>2024-08-31T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Node.js"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;If you are sending a &lt;code&gt;FormData&lt;/code&gt; body with &lt;code&gt;fetch&lt;/code&gt;,
things might not work correctly if you are (accidentally)
setting the &lt;code&gt;Content-Type&lt;/code&gt; request header to &lt;code&gt;&amp;quot;application/json&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was sending a &lt;code&gt;FormData&lt;/code&gt; object to a 3rd party API:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formData &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;FormData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
formData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; someValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'https://example.com/api/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; formData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The API responses were confusing/incorrect.&lt;/p&gt;
&lt;h2 id=&quot;culprit&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#culprit&quot;&gt;Culprit&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was using &lt;code&gt;request&lt;/code&gt;,
which is a thin wrapper around &lt;code&gt;fetch&lt;/code&gt;.
Something like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestInit&lt;span class=&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; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&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;options&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      Accept&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      apiKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'abc123'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&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;options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&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; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Handle errors etc.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how I'm defaulting the &lt;code&gt;Content-Type&lt;/code&gt; header to &lt;code&gt;&amp;quot;application/json&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is handy because most of the time I'm sending JSON.&lt;/p&gt;
&lt;p&gt;But now I was sending a &lt;code&gt;FormData&lt;/code&gt; object,
so the implicit &lt;code&gt;&amp;quot;application/json&amp;quot;&lt;/code&gt; value caused problems.&lt;/p&gt;
&lt;p&gt;It took me a while to realize
that this was the culprit for the confusing API responses.&lt;/p&gt;
&lt;h2 id=&quot;fix-attempt-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fix-attempt-1&quot;&gt;Fix attempt 1&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First I tried to &amp;quot;clear&amp;quot; the default &lt;code&gt;Content-Type&lt;/code&gt; value:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'https://example.com/api/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; formData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  headers&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-property property&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&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;
  method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But whoops,
it caused a TypeScript error (header values must be strings),
and the value was set to the string &lt;code&gt;&amp;quot;undefined&amp;quot;&lt;/code&gt;.
Not good.&lt;/p&gt;
&lt;h2 id=&quot;fix-attempt-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fix-attempt-2&quot;&gt;Fix attempt 2&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Then I tried to set the value to &lt;code&gt;&amp;quot;multipart/form-data&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'https://example.com/api/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; formData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  headers&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-property property&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'multipart/form-data'&lt;/span&gt;&lt;span class=&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;
  method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this didn't work either.&lt;/p&gt;
&lt;h2 id=&quot;explanation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#explanation&quot;&gt;Explanation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This snippet makes it clear why the 2nd fix attempt didn't work:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formData &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;FormData&lt;/span&gt;&lt;span class=&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; req &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;Request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'https://example.com/api/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; formData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&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 builtin&quot;&gt;console&lt;/span&gt;&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 operator&quot;&gt;...&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['content-type', 'multipart/form-data; boundary=---------------------------26864524337159351664014536661']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So my &lt;code&gt;Content-Type&lt;/code&gt; header value (&lt;code&gt;&amp;quot;multipart/form-data&amp;quot;&lt;/code&gt;)
was missing a &lt;code&gt;boundary&lt;/code&gt; value,
which is automatically generated by the browser (or Node.js or whatever)
and actually required.&lt;/p&gt;
&lt;p&gt;From &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Content-Type&lt;/code&gt; on MDN&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For multipart entities, the &lt;code&gt;boundary&lt;/code&gt; parameter is required.
It is used to demarcate the boundaries of the multiple parts of the message.
[...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;[A &lt;code&gt;multipart/form-data&lt;/code&gt;] request looks something like the following example with some headers omitted for brevity.
In the request, a boundary of &lt;code&gt;ExampleBoundaryString&lt;/code&gt; is used for illustration,
but in practice, a browser would create a string more like this &lt;code&gt;---------------------------1003363413119651595289485765&lt;/code&gt;.&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-http bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token request-line&quot;&gt;&lt;span class=&quot;token method property&quot;&gt;POST&lt;/span&gt; &lt;span class=&quot;token request-target url&quot;&gt;/foo&lt;/span&gt; &lt;span class=&quot;token http-version property&quot;&gt;HTTP/1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;68137&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;multipart/form-data; boundary=ExampleBoundaryString&lt;/span&gt;&lt;/span&gt;

--ExampleBoundaryString
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Disposition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;form-data; name=&quot;description&quot;&lt;/span&gt;&lt;/span&gt;

Description input value
--ExampleBoundaryString
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Disposition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;form-data; name=&quot;myFile&quot;; filename=&quot;foo.txt&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;text/plain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token text-plain&quot;&gt;
[content of the file foo.txt chosen by the user]
--ExampleBoundaryString--
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;final-fix&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#final-fix&quot;&gt;Final fix&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The implicit &lt;code&gt;Content-Type: &amp;quot;application/json&amp;quot;&lt;/code&gt; was the root cause,
so I got rid of it.
Well, at least partially:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestInit&lt;span class=&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; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&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;options&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      Accept&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      apiKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'abc123'&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;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FormData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&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;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if the &lt;code&gt;body&lt;/code&gt; is a &lt;code&gt;FormData&lt;/code&gt; object,
&lt;code&gt;fetch&lt;/code&gt; automatically sets the &lt;code&gt;Content-Type&lt;/code&gt; header to &lt;code&gt;multipart/form-data&lt;/code&gt;
with an automatically generated &lt;code&gt;boundary&lt;/code&gt; value.&lt;/p&gt;
&lt;h2 id=&quot;lessons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#lessons&quot;&gt;Lessons&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My first thought was that while this hand-rolled wrapper around &lt;code&gt;fetch&lt;/code&gt; has been handy,
maybe it would have been better to use a battle-tested library from the beginning.
For example,
&lt;a href=&quot;https://github.com/sindresorhus/ky&quot; class=&quot;link link-external&quot;&gt;Ky (&amp;quot;a tiny and elegant HTTP client based on the Fetch API&amp;quot;)&lt;/a&gt;
seems nice.&lt;/p&gt;
&lt;p&gt;Or, at least, one should be careful about default/implicit values.&lt;/p&gt;
&lt;p&gt;I wonder if the 3rd party API server should also be validating the request headers.
The API endpoint expects a &lt;code&gt;FormData&lt;/code&gt; body,
so maybe it should also check that the &lt;code&gt;Content-Type&lt;/code&gt; request header is valid.
It would be a small thing to do,
but it would have saved me a great amount of time.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/relative-tr-in-safari/</id><title>Safari doesn't support `position: relative` on `&lt;tr&gt;` elements</title><link href="https://mtsknn.fi/blog/relative-tr-in-safari/" /><published>2024-06-11T12:00:00+03:00</published><updated>2024-06-11T12:00:00+03:00</updated><category term="CSS"></category><category term="Safari"></category><content type="html">&lt;p&gt;This is a problem if you want whole table rows to be clickable.
Luckily there's a (hacky) workaround.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I want whole table rows (&lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt;s) to be clickable.&lt;/p&gt;
&lt;p&gt;I don't want to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wrap the &lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt;s in &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements either
because that wouldn't be semantic.
(Not sure if this would even work; haven't tested.)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;onClick&lt;/code&gt; on the &lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt; elements
because that wouldn't be accessible.&lt;/li&gt;
&lt;li&gt;Use an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element in each table cell (&lt;code&gt;&amp;lt;td&amp;gt;&lt;/code&gt;)
because that's not the same thing
and this wouldn't be accessible either (duplicate links).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I use the &lt;code&gt;::after&lt;/code&gt; pseudo-element trick
to expand a link's clickable area to cover the whole table row:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;table&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;thead&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;tr&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;th&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Name&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;th&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;th&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Age&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;th&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;th&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Eye color&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;th&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;th&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;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&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;Read more&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &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;th&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;tr&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;thead&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;tbody&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;tr&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;td&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;John&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;td&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;td&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;22&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;td&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;td&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Blue&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;td&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;td&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&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;Read more about John&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;#&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;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;td&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;tr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&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;tbody&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;table&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;tr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;a::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/* Debug outline */&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -3px&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgzgpgNhDGAuEAmIBcIB0sxhAGhADMBLGXVAbVADsBDAWwjUwAt56p8RYB7axfswA8LAIwA+AAoQeABxhCA9GPEAdauqHxaAIxhrqAAkNaWEWkgPHjWgE5XrN+C0O0oxAObUAvKpAxCeD9xADkGCCVnB0dTV3cvXxBbTzZggEEPCMUo9UcnFzdPHz8AoJBxAFEATwhDXigeW0iWaOtYwoSSiEDg3LybMFlaI1goWhxEgDdiMABXNygqgFoWYiQkCA1ygCVzJEN6RqzB4dabbJa+8-h7Pua9hy0dHiQq1rszk3hLACkeFmokUsVza3ziRUSyQ8qXKACZYUDPlpLAAhKCzLLfJFYkExWiuZK0JZjHTQRK7CwHI6uZ6zeCGP4AvyGFi2bqJADEwUASYRKWhI7LAoxtbK3YVOMX9ZGhYiwADWiNxX32HWKSRSZXEAGYAJyK8Wg1G2HgAd0BguxQv6NnxtEJxN0ZL8FP2hzZNJ4dMMIVlcuZrPZfi55V5in5Sv1MVF7xulvEaUY7kxVryyPBnXV0M1ogAbJHU1iAOJszb5mI4g14gnEIkkp0gF1U926T30hPQYgQf1swicnl8gUVqOxu7ZZ6vAyRXT6dRcSAwBDEPjkEAAFgADKh1yAAL54GjhZhYHBcXj8TbwZg3QzAPqyHhgYjwJfUVCGNljZ+TCAAbnUO-UdRaFQVBaECCBbBvPozwEeA3z8Pw-2FYhqEgODDHXJDjHvR9nz4N9dDAHh0UQJC+kUAAqQwABEIB0WYPEMVt3GoWoKMUPpmJQiA31hWQAA9DCI9x9hYHh4FkFC5Swpi6RYiAlh4QhCDQt8li1ASkIAjRqEowwKmofYlPfaAIEmYZ6TAeAqjIQx2MA-hp1qW9hWeWwNlsJZ6jGWRIDfbzaF839-wcm5UBYcYAApwp4b9bAASkMMEXOMHRaHlDxjVmQyvOIxo3w5CAiq00KWDwdRkrvCwkBQjw33XDAAFY2XoEqdOccr+FsVBqHE6KxisrzVigJBEsq1zGg8pZnngeAeHoN9RAEoTiLWNq51Mxdl2YLUtS3XcAF0dyAA&quot; class=&quot;link link-external&quot;&gt;Demo of the problem on Flems.io.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(This is a crude-ish example;
see e.g. &lt;a href=&quot;https://adrianroselli.com/2023/11/dont-turn-a-table-into-an-aria-grid-just-for-a-clickable-row.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Don't Turn a Table into an ARIA Grid Just for a Clickable Row&lt;/em&gt; by Adrian Roselli&lt;/a&gt;
for tips on accessibility.)&lt;/p&gt;
&lt;p&gt;Works well e.g. in Firefox:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./problem-firefox.png&quot; alt=&quot;Screenshot of Firefox showing that the problem is not a problem: the links' debug outlines cover the table rows.&quot;&gt;&lt;/p&gt;
&lt;p&gt;But Safari doesn't support &lt;code&gt;position: relative&lt;/code&gt; on table rows,
so the &lt;code&gt;::after&lt;/code&gt; element is way too big – it covers the whole viewport:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./problem-safari.png&quot; alt=&quot;Screenshot of Safari showing the problem: the links' debug outlines cover the whole viewport.&quot;&gt;&lt;/p&gt;
&lt;p&gt;In effect, clicking anywhere on the page (above the fold if the page is scrollable) triggers the link on the last table row!&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;step-1-alternative-for-position-relative&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-1-alternative-for-position-relative&quot;&gt;Step 1: alternative for &lt;code&gt;position: relative&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-css&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-css&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-css&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-css&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found this from &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/1899&quot; class=&quot;link link-external&quot;&gt;a GitHub issue in the w3c/csswg-drafts repo: &lt;em&gt;[css-position][css-tables] position doesn't apply on &lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt; either&lt;/em&gt;&lt;/a&gt;,
from &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/1899#issuecomment-338773780&quot; class=&quot;link link-external&quot;&gt;a comment by Oriol Brufau&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/1899#issuecomment-1761309439&quot; class=&quot;link link-external&quot;&gt;Honza Kopecký commented&lt;/a&gt;
in Oct 2023 that &amp;quot;both Safari and Chrome on iOS don't work and the hack doesn't help either,&amp;quot;
but in my testing (Jun 2024) the hack does work in Safari on iPadOS v17.4.1.&lt;/p&gt;
&lt;p&gt;Two more relevant things that I found:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=240961&quot; class=&quot;link link-external&quot;&gt;WebKit bug report: &lt;em&gt;&lt;code&gt;position: relative&lt;/code&gt; doesn't work as expected on table row&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/51843534/1079869&quot; class=&quot;link link-external&quot;&gt;Stack Overflow question: &lt;em&gt;Bug in most browsers?: Ignoring position relative on 'tbody', 'tr' and 'td'?&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-2-still-too-big&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-2-still-too-big&quot;&gt;Step 2: still too big&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now the links' clickable areas are smaller,
but still too big in Safari;
they are as tall as the whole table:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./step-2-safari.png&quot; alt=&quot;Screenshot of Safari showing that step 1 fixed the problem only partially: the links' debug outlines are still too big.&quot;&gt;&lt;/p&gt;
&lt;p&gt;In effect, the last link's clickable area expands below the table,
but otherwise the table rows are properly clickable.&lt;/p&gt;
&lt;p&gt;I found a solution from
&lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/1899#issuecomment-1232707455&quot; class=&quot;link link-external&quot;&gt;a GitHub comment by Loz Calver&lt;/a&gt;
under the aforementioned GitHub issue:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If your only issue is absolutely positioned elements overflowing the table-row (e.g. absolutely positioned anchors to make a full row clickable),
another possible workaround is to use &lt;code&gt;tr { clip-path: inset(0); }&lt;/code&gt;.
It causes some strange paint side-effects in Safari,
like borders sometimes disappearing,
but it does at least clip child elements as expected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-css&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-css&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-css&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-focus-outlines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-3-focus-outlines&quot;&gt;Step 3: focus outlines&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because of the &lt;code&gt;clip-path&lt;/code&gt; used in step 2,
make sure you use negative &lt;code&gt;outline-offset&lt;/code&gt; for the table rows' focus styles,
or the focus styles will also be clipped and invisible:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-css&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-css&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;tr:focus-within&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Needs to be negative because of the `clip-path` above */&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token inserted-sign inserted language-css&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;a:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* The focus styles are on the table row */&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-css&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token selector&quot;&gt;a::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token deleted-sign deleted language-css&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* Debug outline */&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;   &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -3px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-css&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;final-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#final-code&quot;&gt;Final code&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/*
    Safari doesn't support `position: relative` on `&amp;lt;tr&gt;` elements,
    but these two properties can be used as an alternative.
    Source: https://mtsknn.fi/blog/relative-tr-in-safari/
  */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;clip-path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;tr:focus-within&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px solid hotpink&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Needs to be negative because of the `clip-path` above */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;a:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* The focus styles are on the table row */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;a::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgzgpgNhDGAuEAmIBcIB0sxhAGhADMBLGXVAbVADsBDAWwjUwAt56p8RYB7axfswA8LAIwA+AAoQeABxhCA9GPEAdauqHxaAIxhrqAAkNaWEWkgPHjWgE5XrN+C0O0oxAObUAvKpAxCeD9xADkGCCVnB0dTV3cvXxBbTzZggEEPCMUo9UcnFzdPHz8AoJBxAFEATwhDXigeW0iWaOtYwoSSiEDg3LybMFlaI1goWhxEgDdiMABXNygqgFoWYiQkCA1ygCVzJEN6RqzB4dabbJa+8-h7Pua9hy0dHiQq1rszk3hLACkeFmokUsVza3ziRUSyQ8qXKACZYUDPlpLAAhKCzLLfJFYkExWiuZK0JZjHTQRK7CwHI6uZ6zeCGP4AvyGFi2bqJADEwUASYRKWhI7LAoxtbK3YVOMX9ZGhYiwADWiNxX32HWKSRSZXEAGYAJyK8Wg1G2HgAd0BguxQv6NnxtEJxN0ZL8FP2hzZNJ4dMMIVlcuZrPZfi55V5in5Sv1MVF7xulvEaUY7kxVryyPBnXV0M1ogAbJHU1iAOJszb5mI4g14gnEIkkp0gF1U926T30hPQYgQf1swicnl8gUVqOxu7ZZ6vAyRXT6dRcSAwBDEPjkEAAFgADKh1yAAL54GjhZhYHBcXj8TbwZg3QzAPqKABUIIAyrRCHbiIYkDwIGBqAByek5lkWRGnpAADECwGIeAl2oVBDDZMYYMmCAwMMPhDDAj40OgCBGH4MA8BBHQvWcH9angE0eEMWRjVkCBbBgn86mGQxSUMWZIBVMBXCMNxEFsOhkIgDBn09WxYAgeC2HgWQwFQRRFHoeAwDlahqAwEhFD0HgPEURDaGEpYbiWYhqCWMBX3fRQ+nvGzhRuYYwEIRp6HgxzqDAJCIAACnXABKABuPpRmIWQliGZx4LMyB4D8oL1B3dQblQFzYE4pYTWg1YjFvYVW3cagpMMWFZAAD0MMAeHcfYWB4WSzLlYL8rpQqICWHhCEIWL4KWUqysCwwH29CBkB4+BqPYoqPEM4gULYuBaE42pOsMMjMNC8LIpYNCW3muzEvUdRaFSnh0p4vLjAKszivXQbhoAFTMQw0s4yr4CqMgCRWox1u0PRamNE1DAO6gkroVBUFfASbxCvgBHgeC-D8ZrjBiiBEcMO6+kg6DYPg3QqvRRBmvB9Rhoqah9lWxCIEmYZAI+r7QeS6dakutjGg2WwlnqMY5OKvnaAF0mjv4WxUBYcYfMlngUNsfy1v2DmdFoeUPGNWYqd56rGngjlRogUWNH4FgiP4ZWcYsJAzI8eD1wwABWNl6GN5KzeSiXqHqmWxjAeBedWKAkEVsEVa5hilmeeAJrcwxRHKyrqrWY251wxdl2YVdYS3XcAF0dyAA&quot; class=&quot;link link-external&quot;&gt;Demo of the final code on Flems.io.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tested with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Edge v125 on Mac&lt;/li&gt;
&lt;li&gt;Firefox v126 on Mac&lt;/li&gt;
&lt;li&gt;Safari v16.6 on Mac&lt;/li&gt;
&lt;li&gt;Safari on iPadOS v17.4.1&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/sounds-like-a-plan/</id><title>&quot;Slap&quot; means &quot;sounds like a plan&quot;</title><link href="https://mtsknn.fi/blog/sounds-like-a-plan/" /><published>2024-03-13T12:00:00+03:00</published><updated>2024-03-13T12:00:00+03:00</updated><category term="English"></category><content type="html">&lt;p&gt;I came up with this acronym myself,
and I'm proud of it!&lt;/p&gt;
&lt;p&gt;I use it often when chatting and conversing with my fam &amp;amp; friends.
Not with my parents though, they wouldn't understand.&lt;/p&gt;
&lt;p&gt;Sometimes I go so far as to say &amp;quot;slapety slap.&amp;quot;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/dbeaver-azure-ad/</id><title>How to use Azure AD authentication in DBeaver</title><link href="https://mtsknn.fi/blog/dbeaver-azure-ad/" /><published>2024-02-28T12:00:00+03:00</published><updated>2024-02-28T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;Alternative title:
How to fix the &amp;quot;Failed to load MSAL4J Java library for performing ActiveDirectoryPassword authentication&amp;quot; error.&lt;/p&gt;
&lt;p&gt;I'm using the free Community Edition of &lt;a href=&quot;https://dbeaver.io/&quot; class=&quot;link link-external&quot;&gt;DBeaver&lt;/a&gt;,
version 23.3.5.&lt;/p&gt;
&lt;p&gt;In the &amp;quot;Connection Settings&amp;quot; pop-up window:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Select e.g. &amp;quot;Active Directory – MFA&amp;quot; as the authentication method and type your username&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./connection-settings-window.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;kbd&gt;Driver Settings&lt;/kbd&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose the &amp;quot;Libraries&amp;quot; tab&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./edit-driver-window.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;kbd&gt;Add Artifact&lt;/kbd&gt; from the right&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the following XML&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-xml bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- https://mvnrepository.com/artifact/com.microsoft.azure/msal4j --&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;dependency&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;groupId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;com.microsoft.azure&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;groupId&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;artifactId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;msal4j&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;artifactId&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;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;1.14.3&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;version&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;dependency&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./edit-maven-artifact-window.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note: the latest version number can be found &lt;a href=&quot;https://mvnrepository.com/artifact/com.microsoft.azure/msal4j&quot; class=&quot;link link-external&quot;&gt;from the URL in the XML comment&lt;/a&gt;,
though the exact version you use might not matter that much&lt;/li&gt;
&lt;li&gt;I found this step from &lt;a href=&quot;https://github.com/dbeaver/dbeaver/issues/15446#issuecomment-1097140996&quot; class=&quot;link link-external&quot;&gt;this GitHub comment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;kbd&gt;OK&lt;/kbd&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;kbd&gt;Download/Update&lt;/kbd&gt; from the right
and &lt;kbd&gt;Download&lt;/kbd&gt; in the opening pop-up window&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;kbd&gt;OK&lt;/kbd&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;kbd&gt;Test Connection ...&lt;/kbd&gt; and authenticate in the opening browser window&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/tricky-mailto-links/</id><title>`mailto:` links with `target=&quot;_blank&quot;` are surprisingly tricky</title><link href="https://mtsknn.fi/blog/tricky-mailto-links/" /><published>2024-02-19T12:00:00+03:00</published><updated>2024-02-19T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Only because Firefox ignores &lt;code&gt;target=&amp;quot;_blank&amp;quot;&lt;/code&gt; in &lt;code&gt;mailto:&lt;/code&gt; links.&lt;/p&gt;
&lt;p&gt;Let's say you have an email link that opens in a new tab:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mailto:hello@example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;target&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;_blank&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;Email 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;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;✅ Clicking the link in Edge works correctly (opens an email client, e.g. Outlook).&lt;/li&gt;
&lt;li&gt;✅ Clicking the link in Safari works correctly (opens an email client).&lt;/li&gt;
&lt;li&gt;✅ If &lt;a href=&quot;https://support.mozilla.org/en-US/kb/change-program-used-open-email-links&quot; class=&quot;link link-external&quot;&gt;Firefox is configured to open an email client when clicking &lt;code&gt;mailto:&lt;/code&gt; links&lt;/a&gt;,
clicking the link works correctly (opens an email client).&lt;/li&gt;
&lt;li&gt;❌ If Firefox is configured to open a webmail (e.g. Gmail) when clicking &lt;code&gt;mailto:&lt;/code&gt; links,
clicking the link opens the webmail in the current tab –
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=646552&quot; class=&quot;link link-external&quot;&gt;Firefox ignores &lt;code&gt;target=&amp;quot;_blank&amp;quot;&lt;/code&gt; in &lt;code&gt;mailto:&lt;/code&gt; links because of a long-standing bug&lt;/a&gt;.
This buggy behavior can be quite annoying.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(I wanted to test how Edge and Safari behave
if they have been configured to open a webmail when clicking &lt;code&gt;mailto:&lt;/code&gt; links,
but configuring this setting in those browsers turned out to be too difficult.&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; smh)&lt;/p&gt;
&lt;p&gt;Based on &lt;a href=&quot;https://stackoverflow.com/a/24854461/1079869&quot; class=&quot;link link-external&quot;&gt;this Stack Overflow answer&lt;/a&gt;,
I tried this kind of &lt;code&gt;onClick&lt;/code&gt; trickery:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;a&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mailto:hello@example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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 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;
    event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'mail'&lt;/span&gt;&lt;span class=&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&gt;
  &lt;span class=&quot;token comment&quot;&gt;// No `target=&quot;_blank&quot;`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  Email me
&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ If Firefox is configured to open a webmail when clicking &lt;code&gt;mailto:&lt;/code&gt; links,
clicking the link works now correctly:
the webmail is opened in a new tab.&lt;/p&gt;
&lt;p&gt;But the UX is degraded in all other cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ Firefox, configured to open &lt;code&gt;mailto:&lt;/code&gt; links in an email client: the new empty tab is left open.&lt;/li&gt;
&lt;li&gt;❌ Edge: the new empty tab is immediately closed, which is great, but causes some jarring flashing.&lt;/li&gt;
&lt;li&gt;❌ Safari: opens a new tab with a confirm dialog: &amp;quot;This website has been blocked from automatically composing an email.&amp;quot;
&lt;ul&gt;
&lt;li&gt;Clicking &amp;quot;Allow&amp;quot; opens an email client, but the new empty tab is left open.&lt;/li&gt;
&lt;li&gt;Clicking &amp;quot;Ignore&amp;quot; leaves the new empty tab open.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was tempted to check if the user's browser is Firefox,
and only then use the &lt;code&gt;onClick&lt;/code&gt; trick.
But trying to detect the user's browser
would open another can of worms.&lt;/p&gt;
&lt;p&gt;In the end I ended up doing nothing about this,
which sucks for some Firefox users,
but I don't know what I could do that wouldn't degrade the UX of any other users. 🤔&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;I did find &lt;a href=&quot;https://christianheilmann.com/2020/07/20/quick-tip-how-to-make-mailto-links-open-in-gmail-in-microsoft-edge/&quot; class=&quot;link link-external&quot;&gt;instructions how configure Edge to open &lt;code&gt;mailto:&lt;/code&gt; links in Gmail&lt;/a&gt;,
but it would require logging in to Gmail,
and I don't want to do that,
because Edge is a shitty browser
(see e.g.
&lt;a href=&quot;https://thomask.sdf.org/blog/2023/03/18/the-dark-defaults-of-microsoft-edge.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;The dark defaults of Microsoft Edge&lt;/em&gt;&lt;/a&gt;
and
&lt;a href=&quot;https://www.neowin.net/news/edge-sends-images-you-view-online-to-microsoft-here-is-how-to-disable-that/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Edge sends images you view online to Microsoft&lt;/em&gt;&lt;/a&gt;).
I use Edge only for testing and occasionally for some web development.
Firefox ftw. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/burp-suite-ux-bad/</id><title>Fix all requests timeouting in Burp Suite's Repeater</title><link href="https://mtsknn.fi/blog/burp-suite-ux-bad/" /><published>2024-02-18T12:00:00+03:00</published><updated>2024-02-18T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;Make sure you are not missing two empty lines after the request headers.
There's a UX lesson here.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was using &lt;a href=&quot;https://portswigger.net/burp&quot; class=&quot;link link-external&quot;&gt;Burp Suite&lt;/a&gt;
(Community Edition, version 2023.12.1.5)
for the first time.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://portswigger.net/burp/documentation/desktop/getting-started/reissuing-http-requests&quot; class=&quot;link link-external&quot;&gt;Sending requests in the Repeater tab&lt;/a&gt;
resulted only in timeouts:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-http bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token response-status&quot;&gt;&lt;span class=&quot;token http-version property&quot;&gt;HTTP/1.1&lt;/span&gt; &lt;span class=&quot;token status-code number&quot;&gt;408&lt;/span&gt; &lt;span class=&quot;token reason-phrase string&quot;&gt;Request Time-out&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;110&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Cache-Control&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;no-cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;close&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;text/html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token text-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;html&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;body&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;408 Request Time-out&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
Your browser didn't send a complete request in time.
&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;body&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;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adding two empty lines after the request headers fixed it for me.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-http bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token request-line&quot;&gt;&lt;span class=&quot;token method property&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;token request-target url&quot;&gt;/wiki/Main_Page&lt;/span&gt; &lt;span class=&quot;token http-version property&quot;&gt;HTTP/1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;en.wikipedia.org&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Accept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;*/*&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-http bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token request-line&quot;&gt;&lt;span class=&quot;token method property&quot;&gt;GET&lt;/span&gt; &lt;span class=&quot;token request-target url&quot;&gt;/wiki/Main_Page&lt;/span&gt; &lt;span class=&quot;token http-version property&quot;&gt;HTTP/1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;en.wikipedia.org&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Accept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;*/*&lt;/span&gt;&lt;/span&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found the solution and an explanation
from &lt;a href=&quot;https://forum.portswigger.net/thread/repeater-request-timeout-45df07ef58c&quot; class=&quot;link link-external&quot;&gt;a thread on Burp Suite User Forum&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Andre:&lt;/strong&gt;
I found a solution to this. I was removing the 2 extra lines from the request when adding the new header. If I keep them, the requests go through. [...]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Diego:&lt;/strong&gt;
I was having the same issue, but like Andre said above, one of the blank lines of the request had been removed. Adding it back made requests in Repeater work again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Uthman, PortSwigger Agent:&lt;/strong&gt;
Thanks for your feedback. You can find more information on why this (&lt;code&gt;\r\n\r\n&lt;/code&gt;) is required in the &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc2616#section-5&quot; class=&quot;link link-external&quot;&gt;RFC 2616 documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;ux-lesson&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#ux-lesson&quot;&gt;UX lesson&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That's terrible UX:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The UI doesn't tell that the two empty lines are required.&lt;/li&gt;
&lt;li&gt;The problem (all requests timeouting) is confusing.
&lt;ul&gt;
&lt;li&gt;I bet most users are not so intimately familiar with RFC 2616
that they can right off the bat deduct that
&amp;quot;Oh, right, all requests seem to be timeouting,
so I must have forgotten the two trailing newlines required in section 5 of RFC 2616!&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How I would fix this UX issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The UI should show a warning or an error if the empty lines are missing.&lt;/li&gt;
&lt;li&gt;Or better yet,
the app should add the missing empty lines automatically
when the user sends a request.
&lt;ul&gt;
&lt;li&gt;To be fair,
the app seems to add the empty trailing lines automatically,
but inconsistently (maybe only when using HTTP/2).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I guess the &amp;quot;UX lesson&amp;quot; can be generalized like so:
communicate obscure requirements to the user,
and auto-fix issues where possible.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/video-games-2023/</id><title>Two great video games I played through in 2023</title><link href="https://mtsknn.fi/blog/video-games-2023/" /><published>2024-02-03T12:00:00+03:00</published><updated>2024-02-03T12:00:00+03:00</updated><category term="Games"></category><content type="html">&lt;p&gt;I managed to find time to play Desperados III and Lost in Play
(and Before Your Eyes too a bit).&lt;/p&gt;
&lt;h2 id=&quot;desperados-iii&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#desperados-iii&quot;&gt;Desperados III&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./desperados-iii.jpg&quot; alt=&quot;Screenshot of Desperados III.&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Screenshot taken from the game's official website.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Desperados III is a story-driven, hardcore tactical stealth game, set in a ruthless Wild West scenario.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;✅ Great visuals&lt;/li&gt;
&lt;li&gt;✅ Nice gameplay (tactical stealth game)&lt;/li&gt;
&lt;li&gt;✅ Plenty of content – Steam shows that I spent 27.5 hours playing the game&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have previously also played the game's predecessor,
&lt;a href=&quot;https://store.steampowered.com/app/418240/Shadow_Tactics_Blades_of_the_Shogun/&quot; class=&quot;link link-external&quot;&gt;Shadow Tactics&lt;/a&gt;,
which is from the same game studio
and has a samurai theme.
It was a great game too.&lt;/p&gt;
&lt;p&gt;Looks like the game studio has released a third similar game last year –
&lt;a href=&quot;https://store.steampowered.com/app/1545560/Shadow_Gambit_The_Cursed_Crew/&quot; class=&quot;link link-external&quot;&gt;Shadow Gambit: The Cursed Crew&lt;/a&gt; –
which has a &amp;quot;cursed pirate crew&amp;quot; theme.
Maybe not the best theme for me,
but at least the gameplay should be great.&lt;/p&gt;
&lt;p&gt;➡️ &lt;a href=&quot;https://desperadosgame.com/&quot; class=&quot;link link-external&quot;&gt;Official website of Desperados III&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;lost-in-play&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#lost-in-play&quot;&gt;Lost in Play&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./lost-in-play.png&quot; alt=&quot;Screenshot of Lost in Play.&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Screenshot taken from the game's official website.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Solve puzzles, riddles, and embark on an exciting journey of discovery! Join Toto and Gal as they explore dreamscapes and befriend magical creatures. Lost in their imagination, the brother and sister must stick together and solve puzzles to find their way home.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;✅ Fantastic music – when I first opened the game,
I got stuck in the main menu for a while because I was jamming to the music!
(The characters' voices are also excellent)&lt;/li&gt;
&lt;li&gt;✅ Fantastic visuals – I really like this kind of art;
the game feels like a great cartoon movie,
except you are in control&lt;/li&gt;
&lt;li&gt;✅ Fun puzzles that got me thinking, but not too hard&lt;/li&gt;
&lt;li&gt;✅ Good, childish humor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Steam shows I spent 4.7 hours playing the game,
so it's a short game, but excellent!&lt;/p&gt;
&lt;p&gt;➡️ &lt;a href=&quot;https://www.happyjuice.games/&quot; class=&quot;link link-external&quot;&gt;Official website of Lost in Play&lt;/a&gt;
(actually the game studio's website, but it doesn't have any subpages as of now)&lt;/p&gt;
&lt;h2 id=&quot;also-before-your-eyes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#also-before-your-eyes&quot;&gt;Also: Before Your Eyes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./before-your-eyes.png&quot; alt=&quot;Screenshot of Before Your Eyes.&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Screenshot taken from the game's official website.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Embark on an emotional first-person narrative adventure where you control the story – and affect its outcomes – with your real-life blinks. With this innovative technique you will fully immerse yourself in a world of memories, both joyous and heartbreaking, as your whole life flashes before your eyes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://hanki.dev/&quot; class=&quot;link link-external&quot;&gt;My bro&lt;/a&gt; gifted me this game as a birthday present (PS thx!).&lt;/p&gt;
&lt;p&gt;Controlling the story with your &amp;quot;real-life blinks&amp;quot;
means that you need a webcam (optional).
Cool and likely quite unique technique,
but a bit wonky and unreliable in the end,
so I disabled it after a while.&lt;/p&gt;
&lt;p&gt;I played this game a few times
but dropped it eventually
because it felt somehow felt so depressing. :D
Maybe too much black all around (see the screenshot),
and because spoiler (read backwards or &lt;button id=&quot;reverse&quot;&gt;click to reverse&lt;/button&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;|: hcum oot deugra stnerap s'tsinogatorp ehT&lt;/p&gt;
&lt;/blockquote&gt;
&lt;script&gt;
  reverse.onclick = function () {
    const blockquote = reverse.parentElement.nextElementSibling
    blockquote.textContent = [...blockquote.textContent].reverse().join('')
  }
&lt;/script&gt;
&lt;p&gt;➡️ &lt;a href=&quot;https://www.beforeyoureyesgame.com/&quot; class=&quot;link link-external&quot;&gt;Official website of Before Your Eyes&lt;/a&gt;
(stupid site because there's zero textual information about the game,
and the &lt;code&gt;&amp;lt;meta name=&amp;quot;description&amp;quot;&amp;gt;&lt;/code&gt; is empty too!)&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/fiction-books-2023/</id><title>Fiction books I read and liked in 2023</title><link href="https://mtsknn.fi/blog/fiction-books-2023/" /><published>2024-01-31T12:00:00+03:00</published><updated>2024-01-31T12:00:00+03:00</updated><category term="Books"></category><content type="html">&lt;p&gt;I started a new hobby in 2023: reading fiction books!
I started with fantasy: Harry Potter, Mistborn, and The Stormlight Archive.&lt;/p&gt;
&lt;h2 id=&quot;harry-potter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#harry-potter&quot;&gt;Harry Potter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After several years of not reading fiction books (almost) at all,
I started my new reading hobby
with this classic heptalogy (= 7-book series)
by J. K. Rowling.&lt;/p&gt;
&lt;p&gt;I have written about Harry Potter before:
&lt;a href=&quot;/blog/harry-potter/&quot; class=&quot;link&quot;&gt;&lt;em&gt;I read all 7 seven Harry Potter books in 33 days&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mistborn&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#mistborn&quot;&gt;Mistborn&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was a great series!
I read all 7 books in the series (trilogy + novella + tetralogy (= 4-book series)).
Brandon Sanderson is such a good writer.&lt;/p&gt;
&lt;p&gt;Three things that are better in Mistborn than in Harry Potter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The magic system is logical and there are clear rules,
whereas in Harry Potter the magic system feels quite random and chaotic (everything seems possible).&lt;/li&gt;
&lt;li&gt;Action scenes are described clearly in Mistborn,
whereas in Harry Potter some scenes are quite unclear,
like &amp;quot;many spells were flying here and there&amp;quot;
(not a direct quote, but I recall especially one scene that was described very vaguely).&lt;/li&gt;
&lt;li&gt;There are multiple viewpoints,
which brings out people's different personalities,
whereas in Harry Potter almost everything is written from the viewpoint of Harry Potter.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-stormlight-archive&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-stormlight-archive&quot;&gt;The Stormlight Archive&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Also by Brandon Sanderson.&lt;/p&gt;
&lt;p&gt;This series is much more heavy than Mistborn –
there are much more characters and places and things etc.&lt;/p&gt;
&lt;p&gt;I'm glad I read Mistborn before this one
because had I started with this,
this would probably have been way too overwhelming.&lt;/p&gt;
&lt;p&gt;So far I have read books 1, 2 and 2.5 (novella),
and I'm waiting for book 3 from the library.&lt;/p&gt;
&lt;h2 id=&quot;dislikes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#dislikes&quot;&gt;Dislikes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I don't want to be Negative Nelly,
so I'll just quickly note why I didn't like some books:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hunger Games (trilogy)
&lt;ul&gt;
&lt;li&gt;Silly premise&lt;/li&gt;
&lt;li&gt;Tacky romance&lt;/li&gt;
&lt;li&gt;First-person perspective (I seem to prefer third-person perspective)&lt;/li&gt;
&lt;li&gt;Present tense (feels weird; I prefer past tense)&lt;/li&gt;
&lt;li&gt;Spoiler (read backwards or &lt;button id=&quot;reverse&quot;&gt;click to reverse&lt;/button&gt;):
&lt;blockquote&gt;
&lt;p&gt;gnitirw yzal ekil tlef dna gniyonna saw hcihw ,tnemom lacitirc yrev a ni drawrof deppiks yrots eht tniop eno tA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;script&gt;
  reverse.onclick = function () {
    const blockquote = reverse.nextElementSibling
    blockquote.textContent = [...blockquote.textContent].reverse().join('')
  }
&lt;/script&gt;
&lt;/li&gt;
&lt;li&gt;I read the whole trilogy despite starting to dislike it quite soon after starting :D :|&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The House in the Cerulean Sea (novel)
&lt;ul&gt;
&lt;li&gt;I had quite high expectations for this
as I had read that this is a good novel to read after Harry Potter&lt;/li&gt;
&lt;li&gt;But this was too slow/boring,
so I dropped this after a few dozen pages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Malazan Book of the Fallen (series)
&lt;ul&gt;
&lt;li&gt;I had read that this is a very heavy series;
someone wrote that you need to read ~300 pages before you &lt;em&gt;might&lt;/em&gt; start to get a grip of the plot&lt;/li&gt;
&lt;li&gt;So yeah, this indeed felt too heavy,
so I dropped this after just a few dozen pages :D&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Assassin's Apprentice (series)
&lt;ul&gt;
&lt;li&gt;First-person perspective (I seem to prefer third-person perspective)&lt;/li&gt;
&lt;li&gt;Too slow/boring beginning,
so I dropped this after a few dozen pages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/ublock-origin-style-operator/</id><title>Tweaking website styles with uBlock Origin filters</title><link href="https://mtsknn.fi/blog/ublock-origin-style-operator/" /><published>2023-11-13T12:00:00+03:00</published><updated>2023-11-13T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;Use the &lt;code&gt;:style()&lt;/code&gt; operator in a uBlock Origin filter
to apply CSS styles to the targeted elements.&lt;/p&gt;
&lt;p&gt;Here's how I use the &lt;a href=&quot;https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#subjectstylearg&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;:style()&lt;/code&gt; operator&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Underline links on &lt;a href=&quot;https://bazqux.com/&quot; class=&quot;link link-external&quot;&gt;BazQux (RSS reader)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Hide points on &lt;a href=&quot;https://hckrnews.com/&quot; class=&quot;link link-external&quot;&gt;hckr news&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Highlight visited comment links on hckr news.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are the filters (under the &amp;quot;My filters&amp;quot; tab in the uBlock Origin dashboard):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;! underline links
bazqux.com##.post .mtext &lt;span class=&quot;token property&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; underline &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

! hide points
hckrnews.com##.entry.row &lt;span class=&quot;token property&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;first-child &lt;span class=&quot;token property&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

! highlight visited comment links
hckrnews.com##.entry.row &lt;span class=&quot;token property&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;first-child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px solid white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -20px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
hckrnews.com##.entry.row &lt;span class=&quot;token property&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;first-child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;outline-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #eee&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I know there's also e.g. &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/styl-us/&quot; class=&quot;link link-external&quot;&gt;Stylus extension for Firefox&lt;/a&gt;,
but the fewer extensions I need,
the better.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/handlebars-else-equals/</id><title>&quot;Else equals&quot; in Handlebars (in SendGrid's Dynamic Templates)</title><link href="https://mtsknn.fi/blog/handlebars-else-equals/" /><published>2023-11-10T12:00:00+03:00</published><updated>2023-11-10T12:00:00+03:00</updated><category term="Handlebars"></category><category term="SendGrid"></category><content type="html">&lt;p&gt;There's a way to do an &amp;quot;else equals&amp;quot; check in Handlebars (in SendGrid's Dynamic Templates),
though it's undocumented and a bit tricky.&lt;/p&gt;
&lt;h2 id=&quot;context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#context&quot;&gt;Context&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.sendgrid.com/for-developers/sending-email/using-handlebars&quot; class=&quot;link link-external&quot;&gt;SendGrid's Dynamic Templates use Handlebars.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://handlebarsjs.com/&quot; class=&quot;link link-external&quot;&gt;Handlebars is a templating language.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wanted to do something like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-handlebars bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{{! Pseudo code, doesn't work }}&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New article: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameEn&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'sv'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Ny artikel: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameSv&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Uusi artikkeli: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameFi&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/if&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it wasn't quite that simple.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;step-by-step&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-by-step&quot;&gt;Step by step&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://handlebarsjs.com/guide/block-helpers.html#conditionals&quot; class=&quot;link link-external&quot;&gt;Handlebar's &lt;code&gt;#if&lt;/code&gt; helper&lt;/a&gt;
checks only the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Truthy&quot; class=&quot;link link-external&quot;&gt;truthiness&lt;/a&gt; of a value;
you can't use &lt;code&gt;==&lt;/code&gt; or other operators,
so &lt;code&gt;{{#if locale == 'en'}}&lt;/code&gt; is invalid.&lt;/li&gt;
&lt;li&gt;You can create &lt;a href=&quot;https://handlebarsjs.com/guide/#custom-helpers&quot; class=&quot;link link-external&quot;&gt;custom Handlebars helpers&lt;/a&gt;.
However,
when using Handlebars in SendGrid,
&lt;a href=&quot;https://stackoverflow.com/q/71501851/1079869&quot; class=&quot;link link-external&quot;&gt;you are limited to SendGrid's Handlebars helpers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Luckily
&lt;a href=&quot;https://docs.sendgrid.com/for-developers/sending-email/using-handlebars#equals&quot; class=&quot;link link-external&quot;&gt;SendGrid provides an &lt;code&gt;#equals&lt;/code&gt; helper&lt;/a&gt;:&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-handlebars bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#equals&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New article: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameEn&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Uusi artikkeli: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameFi&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/equals&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;But whoops,
&lt;a href=&quot;https://stackoverflow.com/q/71427569/1079869&quot; class=&quot;link link-external&quot;&gt;Handlebars helpers create new scopes&lt;/a&gt;,
so &lt;code&gt;{{articleNameEn}}&lt;/code&gt; and &lt;code&gt;{{articleNameFi}}&lt;/code&gt; are &amp;quot;empty.&amp;quot;
Need to use the &lt;code&gt;@root&lt;/code&gt; keyword:&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-handlebars bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-handlebars&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#equals&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-handlebars&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New article: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameEn&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-handlebars&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New article: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameEn&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-handlebars&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-handlebars&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Uusi artikkeli: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameFi&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-handlebars&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Uusi artikkeli: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameFi&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-handlebars&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/equals&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;And how to do &amp;quot;else equals&amp;quot;?
The documentation doesn't tell.
But &lt;a href=&quot;https://docs.sendgrid.com/for-developers/sending-email/using-handlebars#basic-if-else-else-if&quot; class=&quot;link link-external&quot;&gt;&amp;quot;else if&amp;quot; is documented&lt;/a&gt;,
so let's try to imitate that:&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-handlebars bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#equals&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New article: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameEn&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;equals&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'sv'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Ny artikel: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameSv&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Uusi artikkeli: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameFi&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/equals&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
This code is syntactically valid and almost works:
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;locale&lt;/code&gt; is &lt;code&gt;'en'&lt;/code&gt;, the first branch is executed.&lt;/li&gt;
&lt;li&gt;But if &lt;code&gt;locale&lt;/code&gt; is &lt;code&gt;'sv'&lt;/code&gt;, the &lt;em&gt;third&lt;/em&gt; branch is executed.
So the second branch (&amp;quot;else equals&amp;quot;) is never executed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Aha! Same gotcha as above.
Because &lt;a href=&quot;https://stackoverflow.com/q/71427569/1079869&quot; class=&quot;link link-external&quot;&gt;Handlebars is so eager to create new scopes&lt;/a&gt;,
need to use the &lt;code&gt;@root&lt;/code&gt; keyword here as well:&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-handlebars bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-handlebars&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#equals&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New article: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameEn&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-handlebars&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;equals&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'sv'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-handlebars&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;equals&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'sv'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-handlebars&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Ny artikel: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameSv&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&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;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Uusi artikkeli: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameFi&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/equals&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;final-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#final-code&quot;&gt;Final code&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-handlebars bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#equals&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New article: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameEn&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;equals&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'sv'&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Ny artikel: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameSv&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Uusi artikkeli: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;articleNameFi&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/equals&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/accept-vs-content-type/</id><title>HTTP headers: Accept vs Content-Type</title><link href="https://mtsknn.fi/blog/accept-vs-content-type/" /><published>2023-11-09T12:00:00+03:00</published><updated>2023-11-09T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;I sometimes forget what these two headers do in requests vs responses,
so here's a refresher for me.&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;Accept&lt;/code&gt; in request headers&lt;/dt&gt;
&lt;dd&gt;What type of response the client expects from the server.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;Accept&lt;/code&gt; in response headers&lt;/dt&gt;
&lt;dd&gt;N/A&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;Content-Type&lt;/code&gt; in request headers&lt;/dt&gt;
&lt;dd&gt;The type of the request data (e.g. in a POST or PUT request).&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;Content-Type&lt;/code&gt; in response headers&lt;/dt&gt;
&lt;dd&gt;The type of the response data.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The &lt;code&gt;Content-Type&lt;/code&gt; header is usually not needed
if the request or response has no data
(e.g. GET requests and 204 No Content responses).
But apparently &lt;a href=&quot;https://stackoverflow.com/a/35722727/1079869&quot; class=&quot;link link-external&quot;&gt;&amp;quot;some servers may require you to provide a &lt;code&gt;Content-Type&lt;/code&gt; [header] in a request even if the request has no payload.&amp;quot;&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/firefox-slowness/</id><title>Cmd-tabing to Firefox on Mac gets progressively slower</title><link href="https://mtsknn.fi/blog/firefox-slowness/" /><published>2023-11-08T12:00:00+03:00</published><updated>2023-11-08T12:00:00+03:00</updated><category term="Mac"></category><content type="html">&lt;p&gt;The longer Firefox is kept open,
the longer it takes for Firefox to receive focus after Cmd-tabing to it.
At some point it can take even about a second,
which really kills the flow.&lt;/p&gt;
&lt;p&gt;I initially thought that maybe the problem is in the &lt;a href=&quot;https://alt-tab-macos.netlify.app/&quot; class=&quot;link link-external&quot;&gt;AltTab app&lt;/a&gt;,
which is an essential Mac app by they way.
But nope, the problem exists even when not using AltTab.&lt;/p&gt;
&lt;p&gt;Then I thought that maybe it's some kind of memory leak,
caused/aggravated by keeping too many Firefox tabs open (a bad habit of mine).
But nope, &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/unload-tabs/&quot; class=&quot;link link-external&quot;&gt;unloading tabs to free resources&lt;/a&gt;
doesn't help either.&lt;/p&gt;
&lt;p&gt;Only restarting Firefox helps,
but that's cumbersome (takes several seconds to do :D).&lt;/p&gt;
&lt;p&gt;Eventually I found
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1808223&quot; class=&quot;link link-external&quot;&gt;a bug report on Bugzilla: &lt;em&gt;cmd-tab back to Firefox window on macOS is slow&lt;/em&gt;&lt;/a&gt;.
From a comment by Stephen A Pohl on Sep 25, 2023:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This bug is next on my list of priorities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yay! Now let's hope the fix is coming soon™.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-default-exports-bad/</id><title>JavaScript's default exports are a footgun</title><link href="https://mtsknn.fi/blog/js-default-exports-bad/" /><published>2023-11-07T12:00:00+03:00</published><updated>2023-11-07T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;It's too easy to accidentally import a default export with a misleading name.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What I have wanted:&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; useSWR &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr'&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; useSWRImmutable &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr/immutable'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;What I have accidentally done (more than once):&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; useSWRImmutable &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr'&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; useSWR &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr/immutable'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
Then I have wasted time being confused
by &lt;a href=&quot;https://swr.vercel.app/&quot; class=&quot;link link-external&quot;&gt;SWR&lt;/a&gt; not working like I expect it to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Named exports would prevent such silly mistakes:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// OK:&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; useSWR &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr'&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; useSWRImmutable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr/immutable'&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Error:&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; useSWRImmutable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr'&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; useSWR &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'swr/immutable'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is why I think it's bad to use default exports (unless you have a good reason).&lt;/p&gt;
&lt;p&gt;Besides,
&lt;a href=&quot;https://www.olivare.net/blog/2023/death-to-default-exports&quot; class=&quot;link link-external&quot;&gt;default exports have other issues as well&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/sorting-anti-symmetry/</id><title>Moving zeros to the end of an array in JavaScript</title><link href="https://mtsknn.fi/blog/sorting-anti-symmetry/" /><published>2023-11-06T12:00:00+03:00</published><updated>2023-11-06T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;Let's learn about anti-symmetry by solving this interview puzzle:
&amp;quot;Move all zeros of an array of integers to the end
while maintaining the relative order of all non-zeros.&amp;quot;&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;moveZeros&lt;/span&gt;&lt;span class=&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 number&quot;&gt;3&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 number&quot;&gt;111&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;57&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 number&quot;&gt;5&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 number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt;      [1, 3,    111, 57,    5,    9, 0, 0, 0]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, ez because there's a great
&lt;a href=&quot;/blog/visual-mnemonic-for-array-sorting/&quot; class=&quot;link&quot;&gt;visual mnemonic for an array sorter's return values&lt;/a&gt;,
so we can simply™ &lt;code&gt;sort()&lt;/code&gt; the values:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;moveZeros&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;numbers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&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;
  numbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toSorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;moveZeros&lt;/span&gt;&lt;span class=&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 number&quot;&gt;3&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 number&quot;&gt;111&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;57&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 number&quot;&gt;5&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 number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt;      [1, 3,    111, 57,    5,    9, 0, 0, 0]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used the new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;toSorted()&lt;/code&gt; method&lt;/a&gt;
to avoid mutating the original array.&lt;/p&gt;
&lt;p&gt;Seems to work with the test input,
but might break with other inputs,
because the comparator function is not &lt;em&gt;anti-symmetric&lt;/em&gt;.
From &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;sort()&lt;/code&gt; on MDN&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[I]f a comparator only returns &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt;,
or only returns &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;-1&lt;/code&gt;,
it will not be able to sort reliably because &lt;em&gt;anti-symmetry&lt;/em&gt; is broken.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So we need to also check if &lt;code&gt;b === 0&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;moveZeros&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;numbers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&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;
  numbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toSorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nested ternaries are icky though,
plus returning &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;-1&lt;/code&gt; is not very clear without comments.&lt;/p&gt;
&lt;p&gt;Final solution:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;moveZeros&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;numbers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&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;
  numbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toSorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&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 comment&quot;&gt;//   a-&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&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 comment&quot;&gt;// &amp;lt;-a&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Keep order&lt;/span&gt;
  &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;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;Though I have to admit that
&lt;a href=&quot;https://gist.github.com/jkumara/d440aa3d3a1c6316eb9909e8c66bb941&quot; class=&quot;link link-external&quot;&gt;Juhani Kumara's solution using &lt;code&gt;reduceRight&lt;/code&gt;&lt;/a&gt;
is annoyingly clever!&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;move0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&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;
  arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduceRight&lt;/span&gt;&lt;span class=&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;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cur&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;acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cur &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'unshift'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'push'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cur&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; acc&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/bulk-logging-hours-in-jira/</id><title>Logging hours to Jira's &quot;Work log&quot; in bulk</title><link href="https://mtsknn.fi/blog/bulk-logging-hours-in-jira/" /><published>2023-11-03T12:00:00+03:00</published><updated>2023-11-03T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;There's apparently no nice way to bulk-log hours in Jira.
Use this One Weird Trick to do it anyway –
Jira consultants HATE it!&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Jira's UI for logging hours (&amp;quot;Work log&amp;quot; / &amp;quot;Time tracking&amp;quot;) is clunky:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It requires lots of mouse clicks and/or key presses.&lt;/li&gt;
&lt;li&gt;It gets very repetitive after a few times.&lt;/li&gt;
&lt;li&gt;The UI keeps changing from time to time, breaking my workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Officially &lt;a href=&quot;https://community.atlassian.com/t5/Jira-questions/How-do-I-bulk-upload-work-hours-for-multiple-tickets-Log-time/qaq-p/1956146&quot; class=&quot;link link-external&quot;&gt;hours can apparently be logged in bulk by importing data from a CSV file&lt;/a&gt;,
but that sounds clunky
and doesn't work if your user account doesn't have permission to import data from CSV files.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Overview:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Track hours in a JS file.&lt;/li&gt;
&lt;li&gt;Log the hours by copy-pasting the code and running it in the browser's JS console.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;tracking-hours&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#tracking-hours&quot;&gt;Tracking hours&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a JavaScript file and keep track of hours with this fancy format:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// @ts-check&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * @type {Record&amp;lt;
 *   `${'Mon' | 'Tue' | 'Wed' | 'Thu' | 'Fri'} 2023-11-${number}`,
 *   [ticketId: `FOO-${number}` | null, hours: number][]
 * &gt;}
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &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 comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;'Wed 2023-11-08'&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 string&quot;&gt;'FOO-123'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// pr fixes&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'FOO-333'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// feature x&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'FOO-444'&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 comment&quot;&gt;// pr review&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;'Tue 2023-11-07'&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 string&quot;&gt;'FOO-222'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// yarn install investigation&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token 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 comment&quot;&gt;// backlog grooming&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'FOO-333'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// feature x&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;'Mon 2023-11-06'&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 string&quot;&gt;'FOO-123'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&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;// nav revamp&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// daily&lt;/span&gt;
  &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use JS instead of TS so that you can later copy-paste the code directly to the browser's JS console.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;// @ts-check&lt;/code&gt; comment at the top lets you still get the benefits of TS;
it makes VS Code nag at you if you get some values wrong.&lt;/li&gt;
&lt;li&gt;Adjust the date and ticket ID types accordingly;
e.g. &lt;code&gt;2023-12-${number}&lt;/code&gt; when it's December
and &lt;code&gt;ABC-${number}&lt;/code&gt; if your Jira ticket IDs start with &lt;code&gt;ABC-&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I'm using &lt;code&gt;null&lt;/code&gt; instead of &lt;code&gt;FOO-${number}&lt;/code&gt; for general stuff because I can't remember the &amp;quot;general stuff&amp;quot; ticket's ID.&lt;/li&gt;
&lt;li&gt;The code comments are for you so you'll remember later how you have been spending your time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;logging-hours&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#logging-hours&quot;&gt;Logging hours&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Initial setup&lt;/h4&gt;
&lt;p&gt;This needs to be done only once.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the browser's DevTools.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Log hours manually in Jira (only one logging needed).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the Network tab of DevTools
and look for the XHR request that was just made.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Right-click on the item and select &amp;quot;Copy as Fetch.&amp;quot;
The code might look something like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;'https://jira.example.com/rest/internal/3/issue/FOO-123/worklog?adjustEstimate=new&amp;amp;newEstimate=0m'&lt;/span&gt;&lt;span class=&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;credentials&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'include'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;headers&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-property property&quot;&gt;'User-Agent'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'redacted for privacy lolz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;Accept&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json,text/javascript,*/*'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'Accept-Language'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'en-US,en;q=0.5'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'X-Atlassian-Capability'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'ISSUE_VIEW'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'Sec-Fetch-Dest'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'empty'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'Sec-Fetch-Mode'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'cors'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'Sec-Fetch-Site'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'same-origin'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;Pragma&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'no-cache'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;'Cache-Control'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'no-cache'&lt;/span&gt;&lt;span class=&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;referrer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'https://jira.example.com/browse/FOO-123'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;'{&quot;timeSpent&quot;:&quot;30m&quot;,&quot;comment&quot;:{&quot;type&quot;:&quot;doc&quot;,&quot;version&quot;:1,&quot;content&quot;:[]},&quot;started&quot;:&quot;2023-10-30T08:00:00.000+0200&quot;}'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'cors'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following snippet to the JS file after the &lt;code&gt;items&lt;/code&gt; object;
notice how I have removed unnecessary Fetch options
and replaced hardcoded values with template strings:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &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 comment&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;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&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;
    date &lt;span class=&quot;token operator&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;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&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 number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// E.g. &quot;Mon 2023-10-23&quot; -&gt; &quot;2023-10-23&quot;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ticketId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      ticketId &lt;span class=&quot;token operator&quot;&gt;??=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'FOO-111'&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;General stuff&quot; ticket&lt;/span&gt;
      time &lt;span class=&quot;token operator&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Hours to minutes&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://jira.example.com/rest/internal/3/issue/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;ticketId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/worklog?adjustEstimate=new&amp;amp;newEstimate=0m&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 literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&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;timeSpent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;time&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;m&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 literal-property property&quot;&gt;comment&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;'doc'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;version&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 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 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;started&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;date&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;T08:00:00.000+0200&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 literal-property property&quot;&gt;headers&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;Accept&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string-property property&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;referrer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://jira.example.com/browse/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;ticketId&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;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There might still be some fluff (I don't know if e.g. the &lt;code&gt;referrer&lt;/code&gt; is needed),
but good enough.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Actually logging&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open Jira in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy-paste the code (including the &lt;code&gt;items&lt;/code&gt; object) to the browser's JS console.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Press &lt;kbd&gt;Enter&lt;/kbd&gt; in the JS console
and switch to the Network tab to monitor whether the Fetch requests succeed or fail.
(So far they have never failed for me (&lt;em&gt;*knocks on wood*&lt;/em&gt;).)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Comment out the logged items in the JS file to avoid accidentally re-logging them the next time:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &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 comment&quot;&gt;// 'Mon 2023-11-06': [&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;//   ...&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ],&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Or just remove the logged items.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nice and easy!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/exact-dependency-versions/</id><title>Pin exact dependency versions</title><link href="https://mtsknn.fi/blog/exact-dependency-versions/" /><published>2023-11-02T12:00:00+03:00</published><updated>2023-11-02T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;In a perfect world,
minor- and patch-level version bumps don't have breaking changes.
In the real world,
things are complicated and shit happens.&lt;/p&gt;
&lt;p&gt;Example: I recently witnessed
&lt;a href=&quot;/blog/yarn-install-failing/&quot; class=&quot;link&quot;&gt;&lt;code&gt;yarn install&lt;/code&gt; starting to fail mysteriously after Node.js was automatically upgraded from v18.16 to v18.18&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had thought that pinning the major-level version number of Node.js
would have prevented this kind of sudden breakages,
but nope.&lt;/p&gt;
&lt;p&gt;Had the Node.js version been pinned to v18.16.1 or even just v18.16,
&lt;code&gt;yarn install&lt;/code&gt; wouldn't have started to &lt;em&gt;suddenly&lt;/em&gt; fail.&lt;/p&gt;
&lt;p&gt;Yes, &lt;code&gt;yarn install&lt;/code&gt; would have probably started to fail later
when upgrading Node.js &lt;em&gt;manually&lt;/em&gt;,
but that's not as bad.
Sudden breakages are worse
because they often require acute investigation,
making your workdays more reactive than proactive.&lt;/p&gt;
&lt;p&gt;So, note to self:
pin exact dependency versions (&lt;code&gt;x.y.z&lt;/code&gt; instead of just &lt;code&gt;x.y&lt;/code&gt; or &lt;code&gt;x&lt;/code&gt;)
to be on the safe side.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/app-insights-error-logging/</id><title>`error.cause` needs to be logged manually to App Insights</title><link href="https://mtsknn.fi/blog/app-insights-error-logging/" /><published>2023-11-01T12:00:00+03:00</published><updated>2023-11-01T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;If you are logging errors to Azure App Insights,
and an Error object has a &lt;code&gt;cause&lt;/code&gt; property (which too could be an Error object),
the &lt;code&gt;cause&lt;/code&gt; Error's &lt;code&gt;message&lt;/code&gt; and &lt;code&gt;stack&lt;/code&gt; properties are not shown in Azure App Insights.
But you can log them manually.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href=&quot;https://github.com/microsoft/ApplicationInsights-node.js&quot; class=&quot;link link-external&quot;&gt;App Insights SDK for Node.js&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the &lt;code&gt;trackException&lt;/code&gt; method
to log an error with a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;cause&lt;/code&gt; property&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; appInsights &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'applicationinsights'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  appInsights&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;defaultClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trackException&lt;/span&gt;&lt;span class=&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;exception&lt;/span&gt;&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;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&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;cause&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; error &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Expected behavior:&lt;/strong&gt;
both Error's message and stack trace are shown in App Insights.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Actual behavior:&lt;/strong&gt;
only the second Error's message (= &lt;code&gt;'bar'&lt;/code&gt;) and stack trace are shown in App Insights.&lt;/p&gt;
&lt;h3 id=&quot;a-less-contrived-example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#a-less-contrived-example&quot;&gt;A less contrived example&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;router&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;'/foo'&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;
  &lt;span class=&quot;token keyword&quot;&gt;try&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; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; database&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFoo&lt;/span&gt;&lt;span class=&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;// This can throw&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&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;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    appInsights&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;defaultClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trackException&lt;/span&gt;&lt;span class=&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;exception&lt;/span&gt;&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;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'GET /foo failed'&lt;/span&gt;&lt;span class=&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;cause&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; error &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Log the first/original Error's &lt;code&gt;stack&lt;/code&gt; property manually:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  appInsights&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;defaultClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trackException&lt;/span&gt;&lt;span class=&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;exception&lt;/span&gt;&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;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&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;properties&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      error &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&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;causeStack&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack &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;undefined&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the first/original Error's message and stack trace will be shown in App Insights
under the &amp;quot;Custom Properties&amp;quot; heading.&lt;/p&gt;
&lt;h3 id=&quot;notes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#notes&quot;&gt;Notes&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;error instanceof Error&lt;/code&gt; check is needed because:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The value of &lt;code&gt;cause&lt;/code&gt; can be of any type.
You should not make assumptions that the error you caught has an &lt;code&gt;Error&lt;/code&gt; as its &lt;code&gt;cause&lt;/code&gt;,
in the same way that you cannot be sure the variable bound in the &lt;code&gt;catch&lt;/code&gt; statement is an &lt;code&gt;Error&lt;/code&gt; either.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Error: cause&lt;/em&gt; on MDN&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No need to include &lt;code&gt;error.message&lt;/code&gt; in the &lt;code&gt;properties&lt;/code&gt; object,
because &lt;a href=&quot;/blog/js-error-stack/&quot; class=&quot;link&quot;&gt;in Node.js, &lt;code&gt;error.stack&lt;/code&gt; also includes the error message&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/regex-numerals/</id><title>`\d` in a regex isn't always equal to `[0-9]`</title><link href="https://mtsknn.fi/blog/regex-numerals/" /><published>2023-10-31T12:00:00+03:00</published><updated>2023-10-31T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Regular expressions"></category><content type="html">&lt;p&gt;In JavaScript, &lt;code&gt;\d&lt;/code&gt; and &lt;code&gt;[0-9]&lt;/code&gt; are equal and match only Arabic numerals (the numbers 0–9).
But in some other languages, &lt;code&gt;\d&lt;/code&gt; matches also non-Arabic numerals.&lt;/p&gt;
&lt;p&gt;There are &lt;a href=&quot;https://www.fileformat.info/info/unicode/category/Nd/list.htm&quot; class=&quot;link link-external&quot;&gt;680 Unicode characters in the &amp;quot;Number, Decimal Digit&amp;quot; category&lt;/a&gt;.
For example:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Characters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Digits (&lt;a href=&quot;https://en.wikipedia.org/wiki/Arabic_numerals&quot; class=&quot;link link-external&quot;&gt;Arabic numerals&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;0123456789&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arabic-Indic digits&lt;/td&gt;
&lt;td&gt;٠١٢٣٤٥٦٧٨٩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extended Arabic-Indic digits&lt;/td&gt;
&lt;td&gt;۰۱۲۳۴۵۶۷۸۹&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NKo digits&lt;/td&gt;
&lt;td&gt;߀߁߂߃߄߅߆߇߈߉&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Devanagari digits&lt;/td&gt;
&lt;td&gt;०१२३४५६७८९&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Testing on &lt;a href=&quot;https://regex101.com/&quot; class=&quot;link link-external&quot;&gt;regex101.com&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://regex101.com/r/64mAxn/1&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;\d&lt;/code&gt; in JavaScript matches 10 of them&lt;/a&gt; (Arabic numerals only)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://regex101.com/r/64mAxn/2&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;\d&lt;/code&gt; in C# matches 370 of them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://regex101.com/r/64mAxn/3&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;\d&lt;/code&gt; in Python matches 540 of them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://regex101.com/r/64mAxn/4&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;\d&lt;/code&gt; in Rust matches all 680&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(I haven't tested whether &lt;code&gt;\d&lt;/code&gt; in those three languages matches also other characters than those 680.)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[0-9]&lt;/code&gt; matches only Arabic numerals in those four languages,
but &lt;a href=&quot;https://unix.stackexchange.com/a/414230&quot; class=&quot;link link-external&quot;&gt;even &lt;code&gt;[0-9]&lt;/code&gt; can't be always trusted&lt;/a&gt;
(a few typos fixed in the quotation):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is generally believed that &lt;code&gt;[0-9]&lt;/code&gt; matches only the ASCII digits &lt;code&gt;0123456789&lt;/code&gt;.
That is painfully false in some instances:
Linux in some locale that is not &amp;quot;C&amp;quot; (June 2020) systems, for example:&lt;/p&gt;
&lt;p&gt;Assume:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'0123456789 ٠١٢٣٤٥٦٧٨٩ ۰۱۲۳۴۵۶۷۸۹ ߀߁߂߃߄߅߆߇߈߉ ०१२३४५६७८९'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try &lt;code&gt;grep&lt;/code&gt; to discover that it allows most of them:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$str&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; -o &lt;span class=&quot;token string&quot;&gt;'[0-9]\+'&lt;/span&gt;
0123456789
٠١٢٣٤٥٦٧٨
۰۱۲۳۴۵۶۷۸
߀߁߂߃߄߅߆߇߈
०१२३४५६७८
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sed&lt;/code&gt; has some troubles.
Should remove only &lt;code&gt;0123456789&lt;/code&gt; but removes almost all digits.
That means that it accepts most digits but not some nines (???):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$str&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'s/[0-9]\{1,\}//g'&lt;/span&gt;
 ٩ ۹ ߉ ९
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even &lt;code&gt;expr&lt;/code&gt; suffers from the same issues as &lt;code&gt;sed&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;expr&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$str&lt;/span&gt;&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;'\([0-9 ]*\)'&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# also matching spaces&lt;/span&gt;
0123456789 ٠١٢٣٤٥٦٧٨
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And also &lt;code&gt;ed&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'%s\n'&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'s/[0-9]/x/g'&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'1,p'&lt;/span&gt; Q &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; ed -v &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$str&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;105&lt;/span&gt;
xxxxxxxxxx xxxxxxxxx٩ xxxxxxxxx۹ xxxxxxxxx߉ xxxxxxxxx९
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Huh. Curious.&lt;/p&gt;
&lt;p&gt;I guess I'd better remember to avoid &lt;code&gt;\d&lt;/code&gt; and prefer &lt;code&gt;[0-9]&lt;/code&gt; or even &lt;code&gt;[0123456789]&lt;/code&gt;
when using other languages than JavaScript.&lt;/p&gt;
&lt;p&gt;When writing JavaScript,
I'll continue using &lt;code&gt;\d&lt;/code&gt; as it's as clear (d = digit) as and shorter than &lt;code&gt;[0-9]&lt;/code&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/response-json-can-throw/</id><title>`response.json()` can throw an error in JavaScript</title><link href="https://mtsknn.fi/blog/response-json-can-throw/" /><published>2023-10-30T12:00:00+03:00</published><updated>2023-10-30T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;If the response body is not valid JSON,
&lt;code&gt;response.json()&lt;/code&gt; will throw,
just like &lt;code&gt;JSON.parse()&lt;/code&gt; would throw
if the same data was passed to it.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &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;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'{ &quot;foo&quot;: true }'&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; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; { foo: true }&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// vs&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &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;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'OK'&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; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quite obvious in hindsight,
but I was wondering this
and couldn't find an answer quickly
(I tried googling &amp;quot;can response.json throw in js&amp;quot;).&lt;/p&gt;
&lt;p&gt;How about &lt;code&gt;response.text()&lt;/code&gt; – can it throw?
No, because it's akin to passing the same data to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/String&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;String()&lt;/code&gt; function&lt;/a&gt;,
which &lt;a href=&quot;https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor&quot; class=&quot;link link-external&quot;&gt;doesn't seem to throw according to the language specs&lt;/a&gt;.
(Compare with &lt;a href=&quot;https://tc39.es/ecma262/multipage/structured-data.html#sec-json.parse&quot; class=&quot;link link-external&quot;&gt;the language specs of &lt;code&gt;JSON.parse()&lt;/code&gt;&lt;/a&gt;;
throwing is mentioned in step 2.)&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-error-stack/</id><title>`error.stack` includes the error message in some JS environments</title><link href="https://mtsknn.fi/blog/js-error-stack/" /><published>2023-10-29T12:00:00+03:00</published><updated>2023-11-02T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;In V8-based JS environments (e.g. Chrome, Deno and Node.js) and in Bun,
&lt;code&gt;error.stack&lt;/code&gt; = error class name + &lt;code&gt;error.message&lt;/code&gt; + stack frames.&lt;/p&gt;
&lt;h2 id=&quot;context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#context&quot;&gt;Context&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was logging an Error object's &lt;code&gt;message&lt;/code&gt; and &lt;code&gt;stack&lt;/code&gt; properties to Azure App Insights
(because &lt;a href=&quot;/blog/app-insights-error-logging/&quot; class=&quot;link&quot;&gt;&lt;code&gt;error.cause&lt;/code&gt; needs to be logged manually to App Insights&lt;/a&gt;),
and was baffled because &lt;code&gt;error.stack&lt;/code&gt; seemed to contain not only the stack trace,
but also the error message.
I thought App Insights was doing something wonky to the Error object.&lt;/p&gt;
&lt;h2 id=&quot;culprit-v8&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#culprit-v8&quot;&gt;Culprit: V8&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Eventually I realized that that's how the &lt;a href=&quot;https://v8.dev/&quot; class=&quot;link link-external&quot;&gt;V8 JS engine&lt;/a&gt; works.
From &lt;a href=&quot;https://v8.dev/docs/stack-trace-api&quot; class=&quot;link link-external&quot;&gt;V8's &lt;em&gt;Stack trace API&lt;/em&gt; docs&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here's an example of a fully formatted stack trace:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-plain bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;ReferenceError: FAIL is not defined
   at Constraint.execute (deltablue.js:525:2)
   at Constraint.recalculate (deltablue.js:424:21)
   at Planner.addPropagate (deltablue.js:701:6)
   at Constraint.satisfy (deltablue.js:184:15)
   at Planner.incrementalAdd (deltablue.js:591:21)
   at Constraint.addConstraint (deltablue.js:162:10)
   at Constraint.BinaryConstraint (deltablue.js:346:7)
   at Constraint.EqualityConstraint (deltablue.js:515:38)
   at chainTest (deltablue.js:807:6)
   at deltaBlue (deltablue.js:879:2)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejs.org/api/errors.html#errorstack&quot; class=&quot;link link-external&quot;&gt;Node.js's &lt;code&gt;error.stack&lt;/code&gt; docs&lt;/a&gt;
say it more explicitly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The first line is formatted as &lt;code&gt;&amp;lt;error class name&amp;gt;: &amp;lt;error message&amp;gt;&lt;/code&gt;,
and is followed by a series of stack frames (each line beginning with &amp;quot;at &amp;quot;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(It's mentioned in &lt;a href=&quot;https://nodejs.org/docs/latest-v4.x/api/errors.html#errors_error_stack&quot; class=&quot;link link-external&quot;&gt;Node.js v4 docs&lt;/a&gt; as well.
&lt;a href=&quot;https://nodejs.org/en/blog/release/v4.0.0&quot; class=&quot;link link-external&quot;&gt;Node.js v4 was released in 2015.&lt;/a&gt;)&lt;/p&gt;
&lt;h2 id=&quot;non-v8-environments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#non-v8-environments&quot;&gt;Non-V8 environments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Firefox and Safari,
&lt;code&gt;error.stack&lt;/code&gt; contains only the stack trace.
Firefox's JS engine is &lt;a href=&quot;https://firefox-source-docs.mozilla.org/js/index.html&quot; class=&quot;link link-external&quot;&gt;SpiderMonkey&lt;/a&gt;;
Safari's JS engine is &lt;a href=&quot;https://trac.webkit.org/wiki/JavaScriptCore&quot; class=&quot;link link-external&quot;&gt;JavaScriptCore&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bun.sh/&quot; class=&quot;link link-external&quot;&gt;Bun&lt;/a&gt; is interesting
because it's also &lt;a href=&quot;https://bun.sh/docs&quot; class=&quot;link link-external&quot;&gt;&amp;quot;powered by JavaScriptCore&amp;quot;&lt;/a&gt;,
but its &lt;code&gt;error.stack&lt;/code&gt; includes the error class name and error message as well.&lt;/p&gt;
&lt;h2 id=&quot;non-standard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#non-standard&quot;&gt;Non-standard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack&quot; class=&quot;link link-external&quot;&gt;The &lt;em&gt;&lt;code&gt;Error.prototype.stack&lt;/code&gt;&lt;/em&gt; page on MDN&lt;/a&gt;
says that it's a non-standard property:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Non-standard:&lt;/strong&gt; This feature is non-standard and is not on a standards track.
Do not use it on production sites facing the Web: it will not work for every user.
There may also be large incompatibilities between implementations and the behavior may change in the future.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using &lt;code&gt;error.stack&lt;/code&gt; on the server is likely a-okay though
(as long as you are familiar with how it works in your JS environment).&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/yarn-install-failing/</id><title>`yarn install` failing mysteriously on Node.js v18.18</title><link href="https://mtsknn.fi/blog/yarn-install-failing/" /><published>2023-10-28T12:00:00+03:00</published><updated>2023-11-02T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;TL;DR: Upgrading Yarn from v1 to v4 fixed it for me.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recently some CI pipelines&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; started to fail at &lt;code&gt;yarn install&lt;/code&gt; (v1.22.19)
with cryptic error messages like these (the error message kept changing):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-plain bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;An unexpected error occurred:
&quot;/path/to/project/node_modules/core-js-pure:
Cannot read properties of undefined (reading 'getOption')&quot;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-plain bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;An unexpected error occurred:
&quot;/path/to/project/node_modules/nodemon:
Cannot read properties of undefined (reading 'getOption')&quot;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-plain bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;An unexpected error occurred:
&quot;/path/to/project/node_modules/spawn-sync:
Cannot read properties of undefined (reading 'config')&quot;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Googling those error messages didn't yield anything useful.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The errors seemed to began after Node.js was upgraded from v18.16 to v18.18.&lt;/p&gt;
&lt;p&gt;Googling &amp;quot;yarn install fails on node.js 18.18.2&amp;quot; (:D)
led me to &lt;a href=&quot;https://github.com/yarnpkg/yarn/issues/3728#issuecomment-1737249792&quot; class=&quot;link link-external&quot;&gt;this GitHub comment on yarnpkg/yarn#3728&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6 years later, NPM removes the node-gyp binary from its bundle with v9.7.2 which is released with Node 18.18.
Breaking our builds because now yarn tries to install &lt;code&gt;node-gyp&lt;/code&gt; automatically and runs every now and then into this issue.
Time to move away from yarn v1. :)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/npm/cli/pull/6554#issuecomment-1726429283&quot; class=&quot;link link-external&quot;&gt;npm/cli#6554 (comment)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Leaving a comment primarily for others running into this problem now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://yarnpkg.com/migration/guide&quot; class=&quot;link link-external&quot;&gt;Upgrading Yarn&lt;/a&gt;
to &lt;a href=&quot;https://yarnpkg.com/blog/release/4.0&quot; class=&quot;link link-external&quot;&gt;Yarn v4, which was released just a few days ago&lt;/a&gt;,
did indeed fix the &lt;code&gt;yarn install&lt;/code&gt; errors.&lt;/p&gt;
&lt;h3 id=&quot;side-comments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#side-comments&quot;&gt;Side comments&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Upgrading to Yarn v2 or v3 might have worked as well (I didn't test).&lt;/li&gt;
&lt;li&gt;I wasn't even aware that there are multiple versions of Yarn.
Maybe because it's not a &amp;quot;normal&amp;quot; dependency.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yarn install&lt;/code&gt; on Yarn v1 typically took about ~1.5 minutes in the CI pipelines,
whereas on Yarn v4 it takes only about ~1 minute.
A nice improvement!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-real-lesson&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-real-lesson&quot;&gt;The real lesson&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The real lesson here is to
&lt;a href=&quot;/blog/exact-dependency-versions/&quot; class=&quot;link&quot;&gt;pin exact dependency version numbers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my case Node.js was automatically upgraded from v18.16 to v18.18
because the version of Node.js was pinned to v18.&lt;/p&gt;
&lt;p&gt;Had the Node.js version been pinned to v18.16.1 or v18.16 instead of just v18,
these errors wouldn't have started suddenly.&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;The CI pipelines were on Azure DevOps.
That's likely irrelevant,
but I still wanted to mention it, because:&lt;/p&gt;
&lt;p&gt;When investigating this problem,
at first I didn't know what's causing it.
One of the Google searches I made was
&amp;quot;azure devops yarn install Cannot read properties of undefined (reading 'config&amp;quot; (:D).&lt;/p&gt;
&lt;p&gt;That search didn't yield any useful results.
This page you are reading now would have been quite useful. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/visual-mnemonic-for-array-sorting/</id><title>Visual mnemonic for an array sorter's return values</title><link href="https://mtsknn.fi/blog/visual-mnemonic-for-array-sorting/" /><published>2023-10-17T12:00:00+03:00</published><updated>2023-10-17T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mnemonics"></category><content type="html">&lt;p&gt;When sorting an array with a custom comparator function,
the function should return &lt;code&gt;&amp;lt;0&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;&amp;gt;0&lt;/code&gt;.
But what do the values do?
Use this weird visual mnemonic –
sorting consultants HATE it!&lt;/p&gt;
&lt;p&gt;First,
recall that an array sorter compares two values, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Second,
because the sorter function should return a number,
imagine an x-axis with the numbers &lt;code&gt;-1&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;+1&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./x-axis.png&quot; alt=&quot;An x-axis with -1, 0 and +1.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now,
realize that &lt;code&gt;-1&lt;/code&gt; is on the left side of the x-axis,
and &lt;code&gt;+1&lt;/code&gt; is on the right side:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Returning &lt;code&gt;-1&lt;/code&gt; (or anything less than zero) from the array sorter
moves &lt;code&gt;a&lt;/code&gt; to the left (before &lt;code&gt;b&lt;/code&gt; in the array).&lt;/li&gt;
&lt;li&gt;Returning &lt;code&gt;+1&lt;/code&gt; (or anything greater than zero) from the array sorter
moves &lt;code&gt;a&lt;/code&gt; to the right (after &lt;code&gt;b&lt;/code&gt; in the array).&lt;/li&gt;
&lt;li&gt;(Returning &lt;code&gt;0&lt;/code&gt; keeps the order of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And why is &lt;code&gt;a&lt;/code&gt; moved relative to &lt;code&gt;b&lt;/code&gt; –
because the array sorter compares two values (&lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;),
and &lt;code&gt;a&lt;/code&gt; comes first in the function parameters (&lt;code&gt;(a, b) =&amp;gt; {}&lt;/code&gt;).
First come, first served.&lt;/p&gt;
&lt;p&gt;Like so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./recap.png&quot; alt=&quot;An x-axis visualizing that when comparing values  and , returning -1 moves  to the left, and returning +1 moves  to the right.&quot;&gt;&lt;/p&gt;
&lt;p&gt;That's it!
To recap:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&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 comment&quot;&gt;// &amp;lt;-a&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&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 comment&quot;&gt;//   a-&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Keep order of `a` and `b`&lt;/span&gt;
&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Illustrations mouse-drawn on &lt;a href=&quot;https://www.tldraw.com/&quot; class=&quot;link link-external&quot;&gt;tldraw.com&lt;/a&gt;.)&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/zod-object-strict/</id><title>Strict object validation is handy for data exploration</title><link href="https://mtsknn.fi/blog/zod-object-strict/" /><published>2023-10-10T12:00:00+03:00</published><updated>2023-10-10T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><category term="Zod"></category><content type="html">&lt;p&gt;Alternative title:
I finally found a good use case for &lt;code&gt;z.object().strict()&lt;/code&gt; in Zod.&lt;/p&gt;
&lt;p&gt;Zod's &lt;code&gt;z.object()&lt;/code&gt; ignores unknown keys (= object keys not specified in a Zod schema) by default.
Unknown keys can be disallowed with &lt;a href=&quot;https://zod.dev/?id=strict&quot; class=&quot;link link-external&quot;&gt;Zod's &lt;code&gt;.strict()&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When would &lt;code&gt;.strict()&lt;/code&gt; be useful?
From &lt;a href=&quot;https://github.com/colinhacks/zod/issues/2062#issuecomment-1455685434&quot; class=&quot;link link-external&quot;&gt;a GitHub comment by Kamil Trebunia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For consuming APIs I would almost always pick &lt;code&gt;z.object&lt;/code&gt;,
but for data exploration as I am doing now &lt;code&gt;z.strictObject&lt;/code&gt; is necessary
and I am glad I found about it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So: if you are exploring what data a poorly documented API returns,
you can use &lt;code&gt;z.object().strict()&lt;/code&gt; (or the shorthand &lt;code&gt;z.strictObject()&lt;/code&gt;)
to avoid missing any keys;
unspecified keys will make Zod throw an error,
so you can adjust the Zod schema accordingly.&lt;/p&gt;
&lt;p&gt;There's no &lt;code&gt;.deepStrict()&lt;/code&gt; method in Zod,
but it's easy to search for &lt;code&gt;.object(&lt;/code&gt; and replace all occurrences with &lt;code&gt;.strictObject(&lt;/code&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/type-safer-node-cache/</id><title>Adding type-safety to Node-Cache</title><link href="https://mtsknn.fi/blog/type-safer-node-cache/" /><published>2023-08-22T12:00:00+03:00</published><updated>2023-08-30T12:00:00+03:00</updated><category term="ESLint"></category><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;Node-Cache (a JS library) has generic &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; methods,
but it's easy to accidentally misuse them.
I made a type-safer wrapper around the library.&lt;/p&gt;
&lt;h2 id=&quot;problem-context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem-context&quot;&gt;Problem / Context&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/node-cache/node-cache&quot; class=&quot;link link-external&quot;&gt;Node-Cache is a caching module for Node.js&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A simple caching module that has &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;delete&lt;/code&gt; methods
and works a little bit like memcached.
Keys can have a timeout (&lt;code&gt;ttl&lt;/code&gt;) after which they expire and are deleted from the cache.
All keys are stored in a single object so the practical limit is at around 1m keys.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Node-Cache's &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; methods are generic, which is nice:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; NodeCache &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'node-cache'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myCache &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;NodeCache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

myCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Foo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cacheKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; foo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; myCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Foo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cacheKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the constructor is &lt;em&gt;not&lt;/em&gt; generic,
which is problematic;
you can accidentally use wrong types when getting and setting values.&lt;/p&gt;
&lt;h3 id=&quot;example-case&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-case&quot;&gt;Example case&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I was investigating a weird bug and was running out of ideas.
Finally I noticed that a single cache was accidentally being used for two different things:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; NodeCache &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'node-cache'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fooCache &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;NodeCache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; barCache &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;NodeCache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fooCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&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;return&lt;/span&gt; fooCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Foo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&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; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getFooFromSomewhere&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  fooCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Foo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; value
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;barCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&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;return&lt;/span&gt; barCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Bar&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&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; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getBarFromSomewhere&lt;/span&gt;&lt;span class=&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;// ⚠️ Whoops! Accidentally using the wrong cache here&lt;/span&gt;
  fooCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Bar&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; value
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;goal&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#goal&quot;&gt;Goal&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ideally the constructor would be generic,
so that a cache can contain only certain types:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fooCache &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;NodeCache&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Foo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; foo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fooCache&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;cacheKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; Foo | undefined&lt;/span&gt;
fooCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cacheKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// `value` must be of type `Foo`&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Currently this is not possible;
&lt;a href=&quot;https://github.com/node-cache/node-cache/issues/273&quot; class=&quot;link link-external&quot;&gt;GitHub issue #273&lt;/a&gt;
is asking for this.&lt;/p&gt;
&lt;p&gt;The issue was created in December 2021,
and the latest commit to the project was made in November 2021,
so the issue might never get solved.&lt;/p&gt;
&lt;p&gt;I solved it myself by creating a type-safer wrapper around Node-Cache.&lt;/p&gt;
&lt;h3 id=&quot;code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#code&quot;&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// eslint-disable-next-line no-restricted-imports&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; NodeCache&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Options&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ValueSetItem &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'node-cache'&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * A type-safer wrapper around [Node-Cache](https://github.com/node-cache/node-cache).
 *
 * Via https://mtsknn.fi/blog/type-safer-node-cache/
 *
 * @example
 * const myCache = Cache&amp;lt;MyType&gt;(options)
 * myCache.set('foo', value)
 * myCache.get('foo')
 *
 * @example
 * // Error: Must provide a type parameter
 * const myCache = Cache(options)
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// A fancy way to make the `T` parameter required:&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// https://stackoverflow.com/a/51173322/1079869&lt;/span&gt;
  options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Options &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Error: Must provide a type parameter (`Cache({})` -&gt; `Cache&amp;lt;T&gt;({})`)'&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Options&lt;span class=&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; cache &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;NodeCache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&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 comment&quot;&gt;// Type casting required to not lose some methods (e.g. `del`)&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;cache &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Required&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; cache&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 comment&quot;&gt;// Only the generic methods of Node-Cache are overridden&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;get&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;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;mget&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;keys&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token 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; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mget&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keys&lt;span class=&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-variable function&quot;&gt;mset&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;keyValueSet&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ValueSetItem&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&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; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mset&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keyValueSet&lt;span class=&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-variable function&quot;&gt;set&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;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ttl&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 builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&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;
      cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ttl &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&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-variable function&quot;&gt;take&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;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Apparently there's no built-in way to mark generic type parameters as required.
So instead of using &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;options: Options&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Options&lt;span class=&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;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...I'm using
&lt;a href=&quot;https://stackoverflow.com/a/51173322/1079869&quot; class=&quot;link link-external&quot;&gt;a fancy way to make the generic &lt;code&gt;T&lt;/code&gt; parameter required&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Options &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Error: Must provide a type parameter (`Cache({})` -&gt; `Cache&amp;lt;T&gt;({})`)'&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Options&lt;span class=&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;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;Cache&lt;/span&gt;&lt;span class=&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;//    ^? Argument of type '{}'&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       is not assignable to parameter of type&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       'Options &amp;amp; &quot;Error: Must provide a type parameter (`Cache({})` -&gt; `Cache&amp;lt;T&gt;({})`)&quot;'.&lt;/span&gt;

&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Foo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&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 comment&quot;&gt;// OK&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately this also makes the &lt;code&gt;options&lt;/code&gt; parameter required.
Passing an empty object is OK.&lt;/p&gt;
&lt;p&gt;Not ideal, but better than nothing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For some reason the spread syntax causes some methods to be lost:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Options&lt;span class=&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; cache &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;NodeCache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&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 operator&quot;&gt;...&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;get&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;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&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; fooCache &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Foo&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&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;
fooCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;del&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       ^? Property 'del' does not exist on type '...'.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type casting fixes the problem (I don't know why):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cache &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Required&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; cache&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 function-variable function&quot;&gt;get&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;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first I used &lt;code&gt;...(cache as Omit&amp;lt;typeof cache, 'get' | 'mget' | 'mset' | 'set' | 'take'&amp;gt;)&lt;/code&gt;,
but &lt;code&gt;...(cache as Required&amp;lt;typeof cache&amp;gt;)&lt;/code&gt;
and &lt;code&gt;...(cache as Readonly&amp;lt;typeof cache&amp;gt;)&lt;/code&gt;
seem to work as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Only the generic methods of Node-Cache need to be overridden;
there's nothing to fix in the non-generic methods (unless I'm missing something).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You might want to copy the JSDoc comments from Node-Cache's &lt;code&gt;index.d.ts&lt;/code&gt;.
For example (comment slightly clarified by me):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 comment&quot;&gt;// ...&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/**
   * Get a cached key and remove it from the cache.
   * Equivalent to calling `get(key)` + `del(key)`.
   *
   * Useful for implementing &quot;single use&quot; mechanism such as OTP (one-time password),
   * where once a value is read it will become obsolete.
   */&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;take&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;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;bonus-eslint&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-eslint&quot;&gt;Bonus: ESLint&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One more step:
use ESLint to prevent importing Node-Cache
so that everyone will use the type-safer wrapper instead.&lt;/p&gt;
&lt;p&gt;There are two built-in ESLint rules for this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-restricted-imports&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;no-restricted-imports&lt;/code&gt;&lt;/a&gt;
to &amp;quot;disallow specified modules when loaded by &lt;code&gt;import&lt;/code&gt;.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-restricted-modules&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;no-restricted-modules&lt;/code&gt;&lt;/a&gt;
to &amp;quot;disallow specified modules when loaded by &lt;code&gt;require&lt;/code&gt;&amp;quot;;
useful if you are still using CommonJS modules.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like so:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-json bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// .eslintc&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;rules&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;no-restricted-imports&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;error&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;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;node-cache&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Import the `Cache` utility instead.&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;
    &lt;span class=&quot;token property&quot;&gt;&quot;no-restricted-modules&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;error&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;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;node-cache&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Import the `Cache` utility instead.&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;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// foo.ts&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; NodeCache &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'node-cache'&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; 'node-cache' import is restricted from being used.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   Import the `Cache` utility instead.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   eslint(no-restricted-imports)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/youtube-transcript-tool/</id><title>YouTube's &quot;Show transcript&quot; tool is great for taking video notes</title><link href="https://mtsknn.fi/blog/youtube-transcript-tool/" /><published>2023-06-28T12:00:00+03:00</published><updated>2023-06-28T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;Incidentally,
it's also great for searching for certain words in a video.&lt;/p&gt;
&lt;p&gt;Click the three dots under a video and then &amp;quot;Show transcript.&amp;quot;
Example screenshot from
&lt;a href=&quot;https://www.youtube.com/watch?v=AKTyPgwfPgg&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Agile Product Ownership in a Nutshell&lt;/em&gt; (15:51) by Henrik Kniberg&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./screenshot.png&quot; alt=&quot;Annotated (1–2–3) screenshot of where to find YouTube's &amp;quot;Show transcript&amp;quot; tool and the transcript.&quot;&gt;&lt;/p&gt;
&lt;p&gt;This tool saves time and effort:
I don't need to be a human speech-to-text machine;
I can instead focus on fixing typos and errors in the transcript
and splitting the text into several paragraphs and bullet points
to make it easier to read.
Two examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/agile-process-visualized/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Video notes: Agile Product Ownership in a Nutshell&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/legacy-code/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Legacy code is code written by other people&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Side note:
I opened an incognito window to take the screenshot,
and uhh... YouTube looks so bloated.
Protip:
block the &lt;code&gt;#related&lt;/code&gt; element (the &amp;quot;related videos&amp;quot; container on the right) with &lt;a href=&quot;https://github.com/gorhill/uBlock&quot; class=&quot;link link-external&quot;&gt;uBlock Origin&lt;/a&gt;
(or use other tools to debloat YouTube).&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/youtube-still-image-bookmarklet/</id><title>Bookmarklet to download still images from YouTube videos</title><link href="https://mtsknn.fi/blog/youtube-still-image-bookmarklet/" /><published>2023-06-27T12:00:00+03:00</published><updated>2023-06-27T12:00:00+03:00</updated><category term="Bookmarklets"></category><category term="JavaScript"></category><content type="html">&lt;p&gt;Quick and dirty code to grab a single frame of a YouTube video.
Might work with other video players too.&lt;/p&gt;
&lt;h2 id=&quot;the-bookmarklet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-bookmarklet&quot;&gt;The bookmarklet&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Drag and drop this to the browser's bookmarks bar:&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;link&quot; href=&quot;javascript:(() =&gt; { const $video = document.querySelector('video'); const { height, width } = $video.getBoundingClientRect(); const $canvas = document.createElement('canvas'); const ctx = $canvas.getContext('2d'); ctx.canvas.height = height; ctx.canvas.width = width; ctx.drawImage($video, 0, 0, width, height); const $a = document.createElement('a'); $a.download = 'frame.png'; $a.href = $canvas.toDataURL(); $a.click(); })()&quot;&gt;YouTube: Download still image&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#usage&quot;&gt;Usage&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open a YouTube video&lt;/li&gt;
&lt;li&gt;Maximize the browser window and use YouTube's &amp;quot;Theater mode&amp;quot; for a larger result&lt;/li&gt;
&lt;li&gt;Pause the video at some point&lt;/li&gt;
&lt;li&gt;Run the bookmarklet; it will download a PNG image&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#code&quot;&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Minified&lt;/h4&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;javascript&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 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; $video &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'video'&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $video&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&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; $canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'canvas'&lt;/span&gt;&lt;span class=&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; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'2d'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$video&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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&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; $a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; $a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;download &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'frame.png'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; $a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDataURL&lt;/span&gt;&lt;span class=&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; $a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Unminified&lt;/h4&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;javascript&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 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; $video &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'video'&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $video&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&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; $canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'canvas'&lt;/span&gt;&lt;span class=&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; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'2d'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$video&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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&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; $a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  $a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;download &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'frame.png'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  $a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDataURL&lt;/span&gt;&lt;span class=&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;
  $a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#next-steps&quot;&gt;Next steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your needs may be different from mine,
but here's what I usually do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://support.apple.com/guide/preview/resize-rotate-or-flip-an-image-prvw2015/mac&quot; class=&quot;link link-external&quot;&gt;Resize the image using Mac's Preview app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Compress the image with &lt;a href=&quot;https://tinypng.com/&quot; class=&quot;link link-external&quot;&gt;TinyPNG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use the image in a blog post&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The end result might have poor quality, but that's all right.
I use this only for getting still images for video notes.&lt;/p&gt;
&lt;p&gt;For an example,
check out yesterday's post,
&lt;a href=&quot;/blog/legacy-code/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Legacy code is code written by other people&lt;/em&gt;&lt;/a&gt;.
Looks good enough for me.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#acknowledgements&quot;&gt;Acknowledgements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I googled for &amp;quot;js video get frame screenshot.&amp;quot;
The first result was &lt;a href=&quot;https://stackoverflow.com/q/19175174/1079869&quot; class=&quot;link link-external&quot;&gt;&amp;quot;&lt;em&gt;Capture frames from video with HTML5 and JavaScript&lt;/em&gt;&amp;quot; question on Stack Overflow&lt;/a&gt;
which gave me a good starting point.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/legacy-code/</id><title>Legacy code is code written by other people</title><link href="https://mtsknn.fi/blog/legacy-code/" /><published>2023-06-26T12:00:00+03:00</published><updated>2023-06-26T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;Legacy code means unfamiliar code.
Legacy code has much more to do with unfamiliarity
than the quality of the code itself.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://www.youtube.com/watch?v=w9YhmMPLQ4U&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Prioritizing Technical Debt as If Time &amp;amp; Money Matters&lt;/em&gt; talk by Adam Tornhill (28:42)&lt;/a&gt;,
from 19:53–22:14:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Legacy code is related to technical debt,
but the two are not the same.&lt;/p&gt;
&lt;p&gt;So what is legacy code?&lt;/p&gt;
&lt;p&gt;There are many definitions out there.
The definition I prefer is that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Legacy code is code that somehow lacks in quality,&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;and more importantly, it's code that we didn't write ourselves.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Right.&lt;/p&gt;
&lt;p&gt;And that second part is really important,
so let me share a story with you.
This is something that happened to me five years ago,
and I've met it several times since then.&lt;/p&gt;
&lt;p&gt;What happened here was that I was visiting our client.
I did a workshop for one of their teams.
We did a hotspot analysis of their code bases.
And they had two code bases.
So we analyzed them.
We talked about them,
discussed how we could address the findings.&lt;/p&gt;
&lt;p&gt;And then, after a while,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;someone in the team mentioned that &amp;quot;You know what? We actually have a third code base as well.&amp;quot;&lt;/li&gt;
&lt;li&gt;So I start to think &amp;quot;Okay, should we analyze that one too?&amp;quot;&lt;/li&gt;
&lt;li&gt;And everyone kind of looked at each other
and laughed a little bit like &amp;quot;Uh, no, we don't really have to do that.&amp;quot;&lt;/li&gt;
&lt;li&gt;So I said &amp;quot;Why not?&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Because we know the third code base is a mess.&amp;quot;&lt;/li&gt;
&lt;li&gt;And I was like &amp;quot;Yeah, we &lt;em&gt;really&lt;/em&gt; have to look at it,&amp;quot; right?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So we did.
And we looked at the hot spot[s],
we looked at the code health metrics,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Cyclomatic_complexity&quot; class=&quot;link link-external&quot;&gt;cyclomatic complexity&lt;/a&gt;,
all that stuff...&lt;/p&gt;
&lt;p&gt;And guess what?
Objectively there was absolutely no difference in code quality between the first two code bases and the third one.&lt;/p&gt;
&lt;p&gt;And you know, when you bring up something like that,
everyone starts to question it,
that &amp;quot;Hey, maybe the tool is measuring the wrong thing;
maybe you are measuring the wrong thing.&amp;quot;
Right?&lt;/p&gt;
&lt;p&gt;So we had to spend a lot of time actually comparing code samples,
and after a while everyone was fairly convinced –
even though they didn't like it –
that code base number three was indeed in no worse shape than the other two.&lt;/p&gt;
&lt;p&gt;So why did everyone think that it was such a mess?&lt;/p&gt;
&lt;p&gt;The reason of course was that
code base number three turned out to be developed in a different part of the organization,
in a team that has since been disbanded.
And this team had simply inherited that code base,
meaning they were now responsible for a piece of code
that they didn't write themselves.
They didn't understand the problem domain,
and they didn't understand the solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So [legacy code] has much more to do with unfamiliarity
than any properties of the code itself.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Makes sense!
Low-quality code can be okay to work with if it's familiar enough.
On the other hand,
unfamiliar code can feel smelly and intimidating at first,
even if it turns out to be of high quality.&lt;/p&gt;
&lt;p&gt;When someone leaves a team or an organization,
they leave behind legacy code
(read: code that is unfamiliar to others),
unless someone else happens to be familiar with all the current code authored by the leaving person.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./adam-tornhill.png&quot; alt=&quot;A snapshot from the video (21:15), with Adam Tornhill on the left and an illustration on the right labeled &amp;quot;The Technical Debt That Wasn't&amp;quot;&quot;&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/date-objects-vs-date-strings/</id><title>`Date` objects are nicer to work with than date strings</title><link href="https://mtsknn.fi/blog/date-objects-vs-date-strings/" /><published>2023-06-25T12:00:00+03:00</published><updated>2023-06-25T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><category term="Zod"></category><content type="html">&lt;p&gt;When parsing data,
date strings should likely be converted to &lt;code&gt;Date&lt;/code&gt; objects.
But beware mutations.&lt;/p&gt;
&lt;h2 id=&quot;intended-audience-applicable-languages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#intended-audience-applicable-languages&quot;&gt;Intended audience / Applicable languages&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post is for you if you are dealing with date strings.&lt;/p&gt;
&lt;p&gt;This post uses JavaScript and TypeScript,
but the main ideas are likely quite language-agnostic.&lt;/p&gt;
&lt;h2 id=&quot;context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#context&quot;&gt;Context&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's say some data from e.g. an API or database contains a date string in ISO format:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  createdOn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'2023-06-25T01:23:45Z'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When validating/parsing the data,
the date string could at the same time be transformed to a &lt;code&gt;Date&lt;/code&gt; object.
(See &lt;a href=&quot;/blog/parse-dont-just-validate/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Parsing data is nicer than only validating it&lt;/em&gt;&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Example using &lt;a href=&quot;https://zod.dev/&quot; class=&quot;link link-external&quot;&gt;Zod, a TypeScript validation library&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'zod'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Schema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  createdOn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&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;&lt;span class=&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;datetime&lt;/span&gt;&lt;span class=&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;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coerce&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&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;// ...&lt;/span&gt;
&lt;span class=&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; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    ^? { createdOn: Date; ... }&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;why-date-objects-are-better&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-date-objects-are-better&quot;&gt;Why &lt;code&gt;Date&lt;/code&gt; objects are better&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;semantically-correct&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#semantically-correct&quot;&gt;Semantically correct&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A date string is not a date;
it's a &lt;a href=&quot;https://en.wikipedia.org/wiki/Serialization&quot; class=&quot;link link-external&quot;&gt;serialized&lt;/a&gt; format of a date.&lt;/p&gt;
&lt;p&gt;When parsing data,
it's semantically correct to convert/deserialize date strings to &lt;code&gt;Date&lt;/code&gt; objects.&lt;/p&gt;
&lt;p&gt;(Not sure if &amp;quot;semantically correct&amp;quot; is the correct term here,
but anyway.)&lt;/p&gt;
&lt;h3 id=&quot;convert-only-once&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#convert-only-once&quot;&gt;Convert only once&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you convert a date string to a &lt;code&gt;Date&lt;/code&gt; object right after receiving the data,
you need to do the conversion only once.&lt;/p&gt;
&lt;p&gt;This avoids shotgun parsing,
or repeating and scattering date parsing here and there.
(More about shotgun parsing in &lt;a href=&quot;/blog/parse-dont-just-validate/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Parsing data is nicer than only validating it&lt;/em&gt;&lt;/a&gt;.)&lt;/p&gt;
&lt;h3 id=&quot;tolocalestring-et-al&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#tolocalestring-et-al&quot;&gt;&lt;code&gt;toLocaleString()&lt;/code&gt; et al.&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you have a &lt;code&gt;Date&lt;/code&gt; object,
you can directly use
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Date.prototype.toLocaleString()&lt;/code&gt;&lt;/a&gt;
and other &lt;code&gt;Date&lt;/code&gt; methods.&lt;/p&gt;
&lt;p&gt;If you have a date string,
you first need to convert the string to a &lt;code&gt;Date&lt;/code&gt; object –
every time you want to use &lt;code&gt;toLocaleString()&lt;/code&gt; (shotgun parsing).&lt;/p&gt;
&lt;p&gt;Even if you have wrapper functions for formatting dates (probably a good thing),
you could make the functions take a &lt;code&gt;Date&lt;/code&gt; argument
instead of a &lt;code&gt;Date | string&lt;/code&gt; argument (simplicity).&lt;/p&gt;
&lt;h3 id=&quot;date-fns-et-al&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#date-fns-et-al&quot;&gt;date-fns et al.&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://date-fns.org/&quot; class=&quot;link link-external&quot;&gt;date-fns is a JavaScript date utility library.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most date-fns functions take &lt;code&gt;Date&lt;/code&gt; arguments, not date string arguments,
so you can do e.g. just &lt;code&gt;startOfWeek(date)&lt;/code&gt;
instead of &lt;code&gt;startOfWeek(parseISO(dateString))&lt;/code&gt; (shotgun parsing, again).&lt;/p&gt;
&lt;h2 id=&quot;beware-mutations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#beware-mutations&quot;&gt;Beware mutations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One drawback is that &lt;code&gt;Date&lt;/code&gt; objects are mutable.
Accidental mutations can lead to hard-to-track bugs;
deliberate mutations can lead to hard-to-reason code.&lt;/p&gt;
&lt;p&gt;This might be not such a big issue if the object is not otherwise guarded;
&lt;code&gt;obj.createdOn.setFullYear(2000)&lt;/code&gt; might not be much worse than any of these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;obj.createdOn = '2000' + obj.createdOn.slice(4)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;obj.name = 'foo'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;obj.items.push('bar')&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyhow,
there are a few ways to avoid &lt;code&gt;Date&lt;/code&gt; mutations
(these are not specific to Zod):&lt;/p&gt;
&lt;h3 id=&quot;use-a-function&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#use-a-function&quot;&gt;Use a function&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Instead of &lt;code&gt;obj.createdOn&lt;/code&gt;, make it a function &lt;code&gt;obj.getCreatedOn()&lt;/code&gt; that creates a new &lt;code&gt;Date&lt;/code&gt; object every time:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; obj &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 function-variable function&quot;&gt;getCreatedOn&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;=&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 string&quot;&gt;'2023-06-25T01:23:45Z'&lt;/span&gt;&lt;span class=&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; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCreatedOn&lt;/span&gt;&lt;span class=&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; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCreatedOn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

a &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; b &lt;span class=&quot;token comment&quot;&gt;//=&gt; false&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt;
If you mutate the &lt;code&gt;Date&lt;/code&gt; object returned by &lt;code&gt;obj.getCreatedOn()&lt;/code&gt;,
the mutation affects only the freshly-created &lt;code&gt;Date&lt;/code&gt; object.
That's better than the mutation affecting who knows how many places.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt;
Some object properties are now functions and some are not,
making the object asymmetrical (&lt;code&gt;obj.name&lt;/code&gt; vs &lt;code&gt;obj.getCreatedOn()&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;use-a-getter-property&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#use-a-getter-property&quot;&gt;Use a getter property&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Very similar to above,
but make &lt;code&gt;obj.createdOn&lt;/code&gt; a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get&quot; class=&quot;link link-external&quot;&gt;getter property&lt;/a&gt; instead:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; obj &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 keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createdOn&lt;/span&gt;&lt;span class=&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;return&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 string&quot;&gt;'2023-06-25T01:23:45Z'&lt;/span&gt;&lt;span class=&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; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createdOn
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createdOn

a &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; b &lt;span class=&quot;token comment&quot;&gt;//=&gt; false&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt;
Same as above + now the object is more symmetrical (&lt;code&gt;obj.name&lt;/code&gt; vs &lt;code&gt;obj.createdOn&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt;
I don't like getters and setters because they are not transparent;
they look like normal object properties, but they are not.&lt;/p&gt;
&lt;h3 id=&quot;use-typescript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#use-typescript&quot;&gt;Use TypeScript&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;TypeScript doesn't have a built-in type for read-only &lt;code&gt;Date&lt;/code&gt;s,
but such a type can be easily created:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ReadonlyDate&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Readonly&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;
  Omit&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;
    Date&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 string&quot;&gt;'setDate'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setFullYear'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setHours'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setMilliseconds'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setMinutes'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setMonth'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setSeconds'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setTime'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setUTCDate'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setUTCFullYear'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setUTCHours'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setUTCMilliseconds'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setUTCMinutes'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setUTCMonth'&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'setUTCSeconds'&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Credit: Daniel Nixon;
the type is from &lt;a href=&quot;https://github.com/date-fns/date-fns/issues/1944&quot; class=&quot;link link-external&quot;&gt;date-fns GitHub issue &lt;em&gt;Suggestion: use a readonly Date type in TypeScript&lt;/em&gt;&lt;/a&gt;.
Also, using &lt;code&gt;Readonly&amp;lt;...&amp;gt;&lt;/code&gt; is probably unnecessary here.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt;
Leverages the type system;
doesn't affect runtime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt;
E.g. date-fns functions don't accept &lt;code&gt;ReadonlyDate&lt;/code&gt; arguments:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Argument of type &lt;code&gt;ReadonlyDate&lt;/code&gt; is not assignable to parameter of type &lt;code&gt;number | Date&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Type &lt;code&gt;ReadonlyDate&lt;/code&gt; is missing the following properties from type &lt;code&gt;Date&lt;/code&gt;: &lt;code&gt;setTime&lt;/code&gt;, &lt;code&gt;setMilliseconds&lt;/code&gt;, &lt;code&gt;setUTCMilliseconds&lt;/code&gt;, &lt;code&gt;setSeconds&lt;/code&gt;, and 11 more.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;use-eslint&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#use-eslint&quot;&gt;Use ESLint&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Date&lt;/code&gt; mutations could be theoretically banned with ESLint.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/eslint-plugin-better-dates&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;eslint-plugin-better-dates&lt;/code&gt;&lt;/a&gt; does this,
but the plugin looks outdated.
It would probably be quite easy to create a similar plugin from scratch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Good:&lt;/strong&gt;
Sounds like a job suitable for ESLint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bad:&lt;/strong&gt;
The plugin looks outdated.&lt;/p&gt;
&lt;p&gt;Using ESLint might be my choice to avoid &lt;code&gt;Date&lt;/code&gt; mutations.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A date string is a serialized format of a date.&lt;/li&gt;
&lt;li&gt;When parsing data,
it's &amp;quot;correct&amp;quot; to deserialize date strings to &lt;code&gt;Date&lt;/code&gt; objects.&lt;/li&gt;
&lt;li&gt;Correctness aside, &lt;code&gt;Date&lt;/code&gt; objects are also nicer to work with.&lt;/li&gt;
&lt;li&gt;Beware accidental mutations of &lt;code&gt;Date&lt;/code&gt; objects.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/harry-potter/</id><title>I read all 7 seven Harry Potter books in 33 days</title><link href="https://mtsknn.fi/blog/harry-potter/" /><published>2023-06-14T12:00:00+03:00</published><updated>2023-06-14T12:00:00+03:00</updated><category term="Books"></category><content type="html">&lt;p&gt;I don't know if I have ever read so much in so short time.
I just liked the books so much.&lt;/p&gt;
&lt;h2 id=&quot;pages-per-day&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pages-per-day&quot;&gt;Pages per day&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here's a table of my reading progress for my own amusement
(books published by Bloomsbury, 2014 editions):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Book&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Pages&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Days&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Average pages per day&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1st&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;332&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;66&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2nd&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;360&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3rd&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;462&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;116&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4th&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;617&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;123&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5th&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;800&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;133&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6th&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;542&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7th&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;620&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;124&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;strong&gt;3,733&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;strong&gt;33&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;strong&gt;113&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There were 33 total days instead of 35
because I started the 4th and 6th books
on the same day as I finished the previous book.&lt;/p&gt;
&lt;h3 id=&quot;lines-per-page&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#lines-per-page&quot;&gt;Lines per page&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The 4th book's text felt smaller
than the first three books' text,
so I had to check:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;28 lines per page&lt;/li&gt;
&lt;li&gt;28&lt;/li&gt;
&lt;li&gt;28&lt;/li&gt;
&lt;li&gt;33&lt;/li&gt;
&lt;li&gt;34 (!)&lt;/li&gt;
&lt;li&gt;33&lt;/li&gt;
&lt;li&gt;33&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So my &amp;quot;pages per day&amp;quot; comparison table is flawed, meh.&lt;/p&gt;
&lt;p&gt;Fun fact: the 5th book is the longest (800 pages),
but it also has the most lines per page,
so it's really a thick book.&lt;/p&gt;
&lt;h2 id=&quot;thoughts-and-spoilers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#thoughts-and-spoilers&quot;&gt;Thoughts and spoilers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;🚨 Spoilers below.&lt;/p&gt;
&lt;h3 id=&quot;easy-english-weird-words&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#easy-english-weird-words&quot;&gt;Easy English, weird words&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The books were easy to read,
but there were also many weird words;
shows that Rowling's favorite school subject was English
(it was mentioned at the end of one of the books).&lt;/p&gt;
&lt;p&gt;Some new-for-me words that I still remember
(these are far from the weirdest words though):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;exasperated (maybe not a new word for me, but I had trouble remembering what this means)&lt;/li&gt;
&lt;li&gt;kissing gate&lt;/li&gt;
&lt;li&gt;palomino&lt;/li&gt;
&lt;li&gt;pensieve&lt;/li&gt;
&lt;li&gt;tabby cat&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;consistent-point-of-view&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#consistent-point-of-view&quot;&gt;Consistent point of view&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Everything revolves around Harry.
If something happens or has happened elsewhere,
it's explained from Harry's point of view;
e.g. Harry has visions,
or someone retells a story for Harry.&lt;/p&gt;
&lt;p&gt;So, the point of view is always consistent,
which makes the books feel coherent.&lt;/p&gt;
&lt;p&gt;I noticed that the last two books break this rule a bit;
they have non-Harry points of view in the first chapter(s).
(I checked and the 1st and 4th books start from different points of view too.)&lt;/p&gt;
&lt;h3 id=&quot;biggest-plot-weakness&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#biggest-plot-weakness&quot;&gt;Biggest plot weakness&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some wizards and witches are totally isolated from the rest of the world (from the Muggle world).
Feels silly.&lt;/p&gt;
&lt;h3 id=&quot;most-boring-scene&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#most-boring-scene&quot;&gt;Most boring scene&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The 4th book (&lt;em&gt;the Goblet of Fire&lt;/em&gt;, the one with the Quidditch World Cup)
has long descriptions of various kinds of tents.
So boring to read about fancy tents!&lt;/p&gt;
&lt;h3 id=&quot;most-anxiety-inducing-scene&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#most-anxiety-inducing-scene&quot;&gt;Most anxiety-inducing scene&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When Harry, Ron and Hermione impersonated Ministry of Magic employees
and infiltrated the Ministry of Magic,
my heart was pounding hard,
and not in a good way.
I don't know why.
I guess I was afraid that they were exposed,
but I don't know why it was so uncomfortable.&lt;/p&gt;
&lt;p&gt;The robbing of Gringotts Wizarding Bank was a similar scene
and also anxiety-inducing, but not as bad.
Possibly because I had already endured the Ministry of Magic scene.&lt;/p&gt;
&lt;p&gt;Both scenes are from the 7th book (&lt;em&gt;the Deathly Hallows&lt;/em&gt;).&lt;/p&gt;
&lt;h3 id=&quot;silly-things&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#silly-things&quot;&gt;Silly things&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Why did Harry, Ron and Hermione have to wear the locket Horcrux at all?!
Would have been better to keep it safe but not wear it.&lt;/li&gt;
&lt;li&gt;Why and how did Dolores Umbridge survive from the centaurs' wrath?&lt;/li&gt;
&lt;li&gt;Harry and others survived many times from very tight spots at the very last minute/second.
Typical, but maybe the survivals could have been less obvious or something like that.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;my-favorite-character&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#my-favorite-character&quot;&gt;My favorite character&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dumbledore because he had so wise things to say.&lt;/p&gt;
&lt;p&gt;My buddy Oskari made an interesting general point:
a great discussion in a book can be very short,
but it's possible that the author has worked on the lines for a long time (several days or even weeks).&lt;/p&gt;
&lt;h3 id=&quot;best-girl&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#best-girl&quot;&gt;Best girl&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I was rooting for Harry and Cho Chang;
a shame it didn't work out.&lt;/p&gt;
&lt;p&gt;I guess Ginny was OK too in the end.
Props for her for the funniest joke:&lt;/p&gt;
&lt;h3 id=&quot;funniest-joke&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#funniest-joke&quot;&gt;Funniest joke&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Weasley twins were often funny,
but the single funniest joke was
in the 6th book (&lt;em&gt;the Half-Blood Prince&lt;/em&gt;), chapter 25:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The fact that Harry Potter was going out with Ginny Weasley seemed to interest a great number of people, most of them girls, yet Harry found himself newly and happily impervious to gossip over the next few weeks. After all, it made a very nice change to be talked about because of something that was making him happier than he could remember being for a very long time, rather than because he had been involved in horrific scenes of Dark Magic.&lt;/p&gt;
&lt;p&gt;'You'd think people had better things to gossip about,' said Ginny, as she sat on the common-room floor, leaning against Harry's legs and reading the Daily Prophet. 'Three Dementor attacks in a week, and all Romilda Vane does is ask me if it's true you've got a Hippogriff tattooed across your chest.'&lt;/p&gt;
&lt;p&gt;Ron and Hermione both roared with laughter. Harry ignored them.&lt;/p&gt;
&lt;p&gt;'What did you tell her?'&lt;/p&gt;
&lt;p&gt;'I told her it's a Hungarian Horntail,' said Ginny, turning a page of the newspaper idly. 'Much more macho.'&lt;/p&gt;
&lt;p&gt;'Thanks,' said Harry, grinning. 'And what did you tell her Ron's got?'&lt;/p&gt;
&lt;p&gt;'A Pygmy Puff, but I didn't say where.'&lt;/p&gt;
&lt;p&gt;Ron scowled as Hermione rolled around laughing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;sweetest-thing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sweetest-thing&quot;&gt;Sweetest thing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Also from the 6th book, chapter 5:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With a sudden exclamation she pointed at the clock's face. Mr Weasley's hand had switched to travelling.&lt;/p&gt;
&lt;p&gt;'He's coming!'&lt;/p&gt;
&lt;p&gt;And sure enough, a moment later there was a knock on the back door. Mrs Weasley jumped up and hurried to it; with one hand on the doorknob and her face pressed against the wood she called softly, 'Arthur, is that you?'&lt;/p&gt;
&lt;p&gt;'Yes,' came Mr Weasley's weary voice. 'But I would say that even if I were a Death Eater, dear. Ask the question!'&lt;/p&gt;
&lt;p&gt;'Oh, honestly …'&lt;/p&gt;
&lt;p&gt;'Molly!'&lt;/p&gt;
&lt;p&gt;'All right, all right … what is your dearest ambition?'&lt;/p&gt;
&lt;p&gt;'To find out how aeroplanes stay up.'&lt;/p&gt;
&lt;p&gt;Mrs Weasley nodded and turned the doorknob, but apparently Mr Weasley was holding tight to it on the other side, because the door remained firmly shut.&lt;/p&gt;
&lt;p&gt;'Molly! I've got to ask you your question first!'&lt;/p&gt;
&lt;p&gt;'Arthur, really, this is just silly …'&lt;/p&gt;
&lt;p&gt;'What do you like me to call you when we're alone together?'&lt;/p&gt;
&lt;p&gt;Even by the dim light of the lantern Harry could tell that Mrs Weasley had turned bright red; he himself felt suddenly warm around the ears and neck, and hastily gulped soup, clattering his spoon as loudly as he could against the bowl.&lt;/p&gt;
&lt;p&gt;'Mollywobbles,' whispered a mortified Mrs Weasley into the crack at the edge of the door.&lt;/p&gt;
&lt;p&gt;'Correct,' said Mr Weasley. 'Now you can let me in.'&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;whats-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-next&quot;&gt;What's next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that I have read the books,
I'm going to watch the Harry Potter movies.
I have never watched them,
except maybe the first one in elementary school.&lt;/p&gt;
&lt;p&gt;I'm also going to continue this new hobby of reading non-fiction books.
No idea about the next books yet though.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/parse-dont-just-validate/</id><title>Parsing data is nicer than only validating it</title><link href="https://mtsknn.fi/blog/parse-dont-just-validate/" /><published>2023-06-13T12:00:00+03:00</published><updated>2023-06-25T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Joi"></category><category term="TypeScript"></category><category term="Zod"></category><content type="html">&lt;p&gt;Parsing encompasses validation,
plus it can increase type-safety,
plus it can transform the data to a better format.
Parse, don't just validate.&lt;/p&gt;
&lt;h2 id=&quot;validation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#validation&quot;&gt;Validation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Validating data means checking if the data matches a certain shape or certain rules.&lt;/p&gt;
&lt;p&gt;For example,
when using &lt;a href=&quot;https://joi.dev/&quot; class=&quot;link link-external&quot;&gt;Joi, a JavaScript validation library&lt;/a&gt;,
you write a schema and check if some data matches the schema:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Joi &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'joi'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userSchema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  createdOn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;isoDate&lt;/span&gt;&lt;span class=&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;
  userName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;min&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;
  userType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;integer&lt;/span&gt;&lt;span class=&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;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&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; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'https://example.com/api/users/123'&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; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; userSchema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&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;else&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; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value
  &lt;span class=&quot;token comment&quot;&gt;//    ^? any&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Validation is essentially a binary check:
the data either is valid or it isn't.&lt;/p&gt;
&lt;p&gt;Well, you do get descriptive validation error messages when using Joi.&lt;/p&gt;
&lt;p&gt;But if the validation passes,
you are none the wiser about the validated data,
at least in terms of type-safety:
the original &lt;code&gt;data&lt;/code&gt; variable has still type &lt;code&gt;unknown&lt;/code&gt;,
and &lt;code&gt;validationResult.value&lt;/code&gt; has type &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While validating data is certainly useful,
the result can be made more useful by parsing the data instead of only validating it.&lt;/p&gt;
&lt;h2 id=&quot;parsing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#parsing&quot;&gt;Parsing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Parsing means processing some input
and converting it to a more precise output.&lt;/p&gt;
&lt;p&gt;Parsing does validation plus more:
parsing = validating data + increasing type-safety + transforming data.&lt;/p&gt;
&lt;h3 id=&quot;parsing-encompasses-validation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#parsing-encompasses-validation&quot;&gt;Parsing encompasses validation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Validation is a more-or-less implicit step of parsing:
if the input data isn't valid (from the parser's perspective),
the parsing can fail.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;JSON.parse&lt;/code&gt;&lt;/a&gt;
parses a JSON string,
and throws if the input is not valid JSON.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Date.parse&lt;/code&gt;&lt;/a&gt;
parses a date string and returns a timestamp,
or &lt;code&gt;NaN&lt;/code&gt; if the input is not a valid date.
&lt;ul&gt;
&lt;li&gt;By the way,
&lt;a href=&quot;/blog/javascripts-date-constructor-is-bad-at-parsing-dates/&quot; class=&quot;link&quot;&gt;&lt;code&gt;Date.parse&lt;/code&gt; is quite bad at parsing dates&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;parsing-can-increase-type-safety&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#parsing-can-increase-type-safety&quot;&gt;Parsing can increase type-safety&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the Joi example above,
Joi could in theory be able to know the result type.&lt;/p&gt;
&lt;p&gt;For example,
if an object schema contains a property with the value of &lt;code&gt;Joi.string()&lt;/code&gt;,
Joi could infer the type of that property to be &lt;code&gt;string | undefined&lt;/code&gt;.&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;But Joi doesn't do that.
It throws away the potential type knowledge acquired during validation.&lt;/p&gt;
&lt;h4&gt;Example: Joi vs Zod&lt;/h4&gt;
&lt;p&gt;One alternative to Joi is
&lt;a href=&quot;https://zod.dev/&quot; class=&quot;link link-external&quot;&gt;Zod, a TypeScript validation library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On the surface,
Zod is used similarly to Joi,
but the critical difference is that Zod can infer the return type of the schema:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-ts&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Joi &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'joi'&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userSchema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  createdOn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;isoDate&lt;/span&gt;&lt;span class=&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 prefix deleted&quot;&gt;-&lt;/span&gt;  userName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;min&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 prefix deleted&quot;&gt;-&lt;/span&gt;  userType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;integer&lt;/span&gt;&lt;span class=&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;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&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&gt;
&lt;span class=&quot;token inserted-sign inserted language-ts&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'zod'&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userSchema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  createdOn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&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;&lt;span class=&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;datetime&lt;/span&gt;&lt;span class=&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 prefix inserted&quot;&gt;+&lt;/span&gt;  userName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&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;&lt;span class=&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;min&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 prefix inserted&quot;&gt;+&lt;/span&gt;  userType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&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;int&lt;/span&gt;&lt;span class=&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;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&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 prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;infer&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; userSchema&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//   ^? {&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//        createdOn: string&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//        userName: string&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//        userType: number&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//      }&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-ts&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'https://example.com/api/users/123'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token deleted-sign deleted language-ts&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; userSchema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;//    ^? any&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token inserted-sign inserted language-ts&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parsingResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; userSchema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;safeParse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parsingResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parsingResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;//    ^? User&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parsingResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;user&lt;/code&gt; variable, which is the result of successful parsing,
has now type &lt;code&gt;User&lt;/code&gt;, which is inferred from the Zod schema.&lt;/p&gt;
&lt;h4&gt;What about &lt;code&gt;JSON.parse&lt;/code&gt;?&lt;/h4&gt;
&lt;p&gt;I used &lt;code&gt;JSON.parse&lt;/code&gt; as an example above
when talking about the validation step of parsing.
But hmm, why doesn't &lt;code&gt;JSON.parse&lt;/code&gt; increase any type-safety...?&lt;/p&gt;
&lt;p&gt;Maybe &lt;code&gt;JSON.parse&lt;/code&gt; should be thought of as a very high-level parser.
The TypeScript &lt;em&gt;compiler&lt;/em&gt; can't have visibility on things happening at &lt;em&gt;runtime&lt;/em&gt;,
like what's passed to &lt;code&gt;JSON.parse&lt;/code&gt;.
If you want type-safety,
you need to be more specific what you ask for,
e.g. by using a type-aware runtime parser like Zod.&lt;/p&gt;
&lt;h3 id=&quot;parsing-can-transform-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#parsing-can-transform-data&quot;&gt;Parsing can transform data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So far I have talked only about validation and type-safety.
What really separates parsing from validation (type-safe or not) is data transformations
(or &amp;quot;data mapping&amp;quot; or &amp;quot;data reserialization&amp;quot;).&lt;/p&gt;
&lt;p&gt;Transforming data means modifying the data to a better format.
Not by mutating the input data&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;,
but by returning a different shape than what was passed to the parser.&lt;/p&gt;
&lt;p&gt;What a &amp;quot;better format&amp;quot; means is up to you.
For example, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trim strings.&lt;/li&gt;
&lt;li&gt;Convert values to different types,
e.g. numerical strings to &lt;code&gt;number&lt;/code&gt;s,
or &lt;a href=&quot;/blog/date-objects-vs-date-strings/&quot; class=&quot;link&quot;&gt;date strings to &lt;code&gt;Date&lt;/code&gt; objects&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set default values for optional or nullable fields.&lt;/li&gt;
&lt;li&gt;Transform object keys from &lt;code&gt;PascalCase&lt;/code&gt; or &lt;code&gt;snake_case&lt;/code&gt; (neither are JavaScript-y) to &lt;code&gt;camelCase&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Rename object keys from a foreign language to English.&lt;/li&gt;
&lt;li&gt;Rename object keys to words that are already used in your code base
to avoid having multiple words for the same thing (data coherency);
e.g. &lt;code&gt;userId&lt;/code&gt; vs &lt;code&gt;personId&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Compute/derive values from other values;
e.g. construct &lt;code&gt;fullName&lt;/code&gt; by combining &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Simplify object structures,
e.g. change &lt;code&gt;Array&amp;lt;{ key: string; value: number }&amp;gt;&lt;/code&gt; to &lt;code&gt;Record&amp;lt;string, number&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Convert comma-separated strings to arrays,
e.g. &lt;code&gt;&amp;quot;1,2,3&amp;quot;&lt;/code&gt; to &lt;code&gt;[1, 2, 3]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Convert number unions to string unions
(see the &lt;code&gt;userSchema&lt;/code&gt; example below).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The point is to modify the data so that it looks like you'd want it to look.&lt;/p&gt;
&lt;p&gt;It's not fun to work with messy data,
but if you transform the data to a nicer format right after receiving it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need to deal with the messy data only once.&lt;/li&gt;
&lt;li&gt;The transformations are centralized to one place
instead of being scattered around everywhere.&lt;/li&gt;
&lt;li&gt;You can write business logic against the ideally shaped data
(as opposed to writing business logic against &amp;quot;someone else's data&amp;quot;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Example: &lt;code&gt;userSchema&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;In the Joi vs Zod example above,
&lt;code&gt;userSchema&lt;/code&gt; and the inferred type look like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'zod'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userSchema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  createdOn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&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;&lt;span class=&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;datetime&lt;/span&gt;&lt;span class=&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;
  userName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&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;&lt;span class=&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;min&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;
  userType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&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;int&lt;/span&gt;&lt;span class=&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;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&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;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;infer&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; userSchema&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ^? {&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//        createdOn: string&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//        userName: string&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//        userType: number&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//      }&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;User&lt;/code&gt; type is quite messy.
If the data is coming from an external API,
the data itself can't be changed...
but the parsed data can be improved by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Converting the &lt;code&gt;createdOn&lt;/code&gt; string to a &lt;code&gt;Date&lt;/code&gt; object,
so you don't need to repeatedly do a conversion from a date string to a &lt;code&gt;Date&lt;/code&gt; object.
&lt;a href=&quot;/blog/date-objects-vs-date-strings/&quot; class=&quot;link&quot;&gt;&lt;code&gt;Date&lt;/code&gt; objects are nicer to work with than date strings.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Converting the &lt;code&gt;userType&lt;/code&gt; number to a string union of &lt;code&gt;'admin' | 'moderator' | 'user'&lt;/code&gt;.
A string union like that is much clearer,
plus then you don't need to repeatedly do a conversion from a number to a string.&lt;/li&gt;
&lt;li&gt;Renaming &lt;code&gt;userName&lt;/code&gt; (uppercase N) to &lt;code&gt;username&lt;/code&gt; (lowercase n)
because &amp;quot;username&amp;quot; is often spelled as a single word.&lt;/li&gt;
&lt;li&gt;Renaming &lt;code&gt;userType&lt;/code&gt; to &lt;code&gt;role&lt;/code&gt; because &lt;code&gt;userType&lt;/code&gt; sounds redundant,
and &lt;code&gt;type&lt;/code&gt; would sound a bit too generic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like so:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;User&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;
  createdOn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Date
  role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'admin'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'moderator'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'user'&lt;/span&gt;
  username&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&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 function&quot;&gt;parseUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&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; User &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; ParseError &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Validate and transform `data`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;How&lt;/em&gt; you transform the data is an implementation detail.
Zod has means for transforming data (another blog post coming later);
you could also transform the data manually.&lt;/p&gt;
&lt;h2 id=&quot;fuzzy-terminology&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fuzzy-terminology&quot;&gt;Fuzzy terminology&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What is parsing?
What is validation?&lt;/p&gt;
&lt;p&gt;Above I said that
parsing = validating data + increasing type-safety + transforming data.
This is based on other sources (see &lt;a href=&quot;#further-resources&quot; class=&quot;link link-anchor&quot;&gt;further resources&lt;/a&gt; below).&lt;/p&gt;
&lt;p&gt;If the data is not transformed,
I guess it could still be called just validation;
be it &amp;quot;type-ignorant&amp;quot; validation (think of Joi)
or type-aware validation (think of Zod).&lt;/p&gt;
&lt;p&gt;In fact,
Joi and Zod are both called validation libraries
even though they also support data transformations.
But that's also a bit confusing.&lt;/p&gt;
&lt;h3 id=&quot;practical-guidelines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#practical-guidelines&quot;&gt;Practical guidelines&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If your intention is to transform the data,
make sure you call it parsing.
Calling it validation would be confusing.&lt;/li&gt;
&lt;li&gt;If your intention is to do only validation:
&lt;ul&gt;
&lt;li&gt;Call it validation or parsing;
choose whichever term and stick to it (be consistent).
Calling it validation would distinguish it from parsing that transforms data,
though I don't know if that would valuable.&lt;/li&gt;
&lt;li&gt;If you call it validation,
make sure you don't transform the data (accidentally or deliberately);
it would be confusing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My other blog posts on this topic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/date-objects-vs-date-strings/&quot; class=&quot;link&quot;&gt;&lt;em&gt;&lt;code&gt;Date&lt;/code&gt; objects are nicer to work with than date strings&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More coming later; I like this topic.&lt;/p&gt;
&lt;h3 id=&quot;main-inspiration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#main-inspiration&quot;&gt;Main inspiration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This blog post is largely inspired by the
&lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Parse, don't validate&lt;/em&gt; blog post by Alexis King&lt;/a&gt;.
Her post has examples in Haskell,
which I'm not familiar with,
but the post was still easy to read.&lt;/p&gt;
&lt;p&gt;These snippets resonated with me the most:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Validation vs parsing:
&lt;blockquote&gt;
&lt;p&gt;[I]n my mind, the difference between validation and parsing lies almost entirely in how information is preserved. [...] Both of [them] check the same thing, but [parsing] gives the caller access to the information it learned, while [validating] just throws it away.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;What is parsing:
&lt;blockquote&gt;
&lt;p&gt;Consider: what is a parser? Really, a parser is just a function that consumes less-structured input and produces more-structured output. [...] Under this flexible definition, parsers are an incredibly powerful tool: they allow discharging checks on input up-front, right on the boundary between a program and the outside world, and once those checks have been performed, they never need to be checked again!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Beware &amp;quot;shotgun parsing&amp;quot;:
&lt;blockquote&gt;
&lt;p&gt;Ad-hoc validation leads to a phenomenon that the &lt;a href=&quot;http://langsec.org/&quot; class=&quot;link link-external&quot;&gt;language-theoretic security&lt;/a&gt; field calls &lt;em&gt;shotgun parsing&lt;/em&gt;. [...]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Shotgun parsing is a programming antipattern whereby parsing and input-validating code is mixed with and spread across processing code [...].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;[...] In other words, a program that does not parse all of its input up front runs the risk of acting upon a valid portion of the input, discovering a different portion is invalid, and suddenly needing to roll back whatever modifications it already executed in order to maintain consistency. Sometimes this is possible – such as rolling back a transaction in an RDBMS – but in general it may not be.&lt;/p&gt;
&lt;p&gt;It may not be immediately apparent what shotgun parsing has to do with validation – after all, if you do all your validation up front, you mitigate the risk of shotgun parsing. The problem is that validation-based approaches make it extremely difficult or impossible to determine if everything was actually validated up front or if some of those so-called &amp;quot;impossible&amp;quot; cases might actually happen. The entire program must assume that raising an exception anywhere is not only possible, it's regularly necessary.&lt;/p&gt;
&lt;p&gt;Parsing avoids this problem by stratifying the program into two phases – parsing and execution – where failure due to invalid input can only happen in the first phase. The set of remaining failure modes during execution is minimal by comparison, and they can be handled with the tender care they require.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Guidelines for parsing –
the blog post contains lots of great points;
these few resonated with me the most:
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;Get your data into the most precise representation you need as quickly as you can. Ideally, this should happen at the boundary of your system, before &lt;em&gt;any&lt;/em&gt; of the data is acted upon.&lt;/p&gt;
&lt;p&gt;If one particular code branch eventually requires a more precise representation of a piece of data, parse the data into the more precise representation as soon as the branch is selected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;[W]rite functions on the data representation you &lt;em&gt;wish&lt;/em&gt; you had, not the data representation you are given. The design process then becomes an exercise in bridging the gap, often by working from both ends until they meet somewhere in the middle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;Don't be afraid to parse data in multiple passes. Avoiding shotgun parsing just means you shouldn't act on the input data before it's fully parsed, not that you can't use some of the input data to decide how to parse other input data. Plenty of useful parsers are context-sensitive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After reading Alexis King's blog post,
I wasn't sure of the relationship between parsing and validation.
These Hacker News (HN) comments were helpful in realizing that
&amp;quot;parse, don't validate&amp;quot; doesn't mean &amp;quot;parse data instead of validating it&amp;quot;;
it means &amp;quot;parse data instead of &lt;em&gt;only&lt;/em&gt; validating it&amp;quot;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=21478870&quot; class=&quot;link link-external&quot;&gt;An HN comment by lexi-labmda (Alexis King)&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;The idea really is that parsing subsumes validation. If you're parsing, you don't have to validate, because validation is a natural side-effect of the parsing process. And indeed, I think that's the very thesis of the blog post: parsing &lt;em&gt;is&lt;/em&gt; validation, just without throwing away all the information you learned once you've finished!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://news.ycombinator.com/item?id=21477645&quot; class=&quot;link link-external&quot;&gt;an HN comment by danharaj&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;The point is not that &amp;quot;parsing&amp;quot; and &amp;quot;validating&amp;quot; are distinct concepts, but that they're two different points of view on the same problem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=27644989&quot; class=&quot;link link-external&quot;&gt;An HN comment by b3morales&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;You seem to suggest that it's possible to parse &lt;em&gt;without&lt;/em&gt; validating, which I'm not sure I follow. Surely validation is just one of the phases or steps of parsing?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=27646359&quot; class=&quot;link link-external&quot;&gt;An HN comment by nsajko&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;The point is that validation is (or should/can be) a byproduct of parsing. I.e., you shouldn't &amp;quot;do both&amp;quot;, rather the validation should be encompassed by the parsing, as much as it makes sense.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://news.ycombinator.com/item?id=35055151&quot; class=&quot;link link-external&quot;&gt;an HN comment by friendzis&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;Validation happens during parsing implicitly: parser will either return a &lt;em&gt;valid&lt;/em&gt; object or throw an error, but parsing has an added benefit that the end result is a datum of a known datatype.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;other-sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#other-sources&quot;&gt;Other sources&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Other helpful things I have stumbled upon,
with a few grammatical fixes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://lobste.rs/s/ot2mea/parse_don_t_validate_2019#c_szw965&quot; class=&quot;link link-external&quot;&gt;a Lobsters comment by kevincox&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;When accepting untrusted input you should not validate it, and accept or reject the user input. You should instead parse and reserialize the input. This ensures that you will only have data that you wrote yourself. It is also natural to throw away unknown fields and simply any odd formatting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://lobste.rs/s/ot2mea/parse_don_t_validate_2019#c_czsiio&quot; class=&quot;link link-external&quot;&gt;a Lobsters comment by jbert&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;Is [the &amp;quot;Parse, don't validate&amp;quot; idea] fundamentally the same idea as &amp;quot;make invalid states unrepresentable&amp;quot;?&lt;/p&gt;
&lt;p&gt;I.e. don't have a corner case of your type where you could have a value which isn't valid (like the empty list), instead tighten your type so that every possible value of the type is valid.&lt;/p&gt;
&lt;p&gt;Looked at this way, any time you have a gap (where your type is too loose and allows invalid states) the consumer of the value of that type needs to check them again. This burden is felt everywhere the type is used.&lt;/p&gt;
&lt;p&gt;If you do the check to ensure you haven't fallen into the gap, take the opportunity to tighten the type to get rid of the gap. I.e. make the invalid state unrepresentable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://lobste.rs/s/8p0q7g/test_against_what_won_t_change#c_s5ecsd&quot; class=&quot;link link-external&quot;&gt;a Lobsters comment by Axman6&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;As a Haskell developer, I've spent a lot of time looking at unit test suites for other languages and thinking &amp;quot;why are you testing that? your type system should make that impossible&amp;quot;, and coming to the realisation that for many languages, their test suite is their type system – but it is an incomplete, sometimes buggy one limited by what the developer was able to predict could go wrong.&lt;/p&gt;
&lt;p&gt;I've always tried to make programs where only valid business logic is possible, and doing this relies heavily on the use of sum types to be precise about what is allowable – I was talking earlier today to someone on IRC about the difference between validating (a.k.a writing code that works with [booleans] to gate progress to other code) and parsing (writing code that produces valid values – perfectly summed up in Alexis King's &lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot; class=&quot;link link-external&quot;&gt;Parse, don't validate&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;At a previous job, we did this religiously, data coming into the program was parsed (in this case from SQS queues), such that we knew in the rest of the system that all our preconditions had been satisfied, and only valid data was allowed within the inner shell of the app. [...]&lt;/p&gt;
&lt;p&gt;The rest of the program was basically implemented in a way that it was very difficult to write incorrect code, all alternatives were represented as subtypes [...].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://itnext.io/parse-dont-validate-incoming-data-in-typescript-d6d5bfb092c8&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Parse, don't validate, incoming data in TypeScript&lt;/em&gt; by Elias Nygren&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;The &lt;em&gt;&amp;quot;parse, don't validate&amp;quot;&lt;/em&gt; mantra is all about parsing incoming data to a specific type, or failing in a controlled manner if the parsing fails. It's about using trusted, safe and typed data structures inside your code and making sure all incoming data is handled at the very edges of your programs. Don't pass incoming data deep into your code, parse it right away and fail fast if needed.&lt;/p&gt;
&lt;p&gt;Parsing is better than just validation because parsing forces you to explicitly handle all incoming data. It gives you a type safe way [of] working and makes it hard to pass around malicious content around your applications and data stores. However, it is true that parsing often includes validating the data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Excerpts from &lt;a href=&quot;https://blog.ploeh.dk/2022/08/22/can-types-replace-validation/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Can types replace validation?&lt;/em&gt; by Mark Seemann&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;The naive take on validation is to answer the question: &lt;em&gt;Is that data valid or invalid?&lt;/em&gt; Notice the binary nature of the question. It's either-or.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;This changes focus on validation. No longer is validation a &lt;em&gt;true/false&lt;/em&gt; question. Validation is a function from less-structured data to more-structured data. &lt;a href=&quot;https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/&quot; class=&quot;link link-external&quot;&gt;Parse, don't validate.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The &amp;quot;This&amp;quot; at the beginning refers to &amp;quot;applicative validation&amp;quot; (I don't know what that is),
but I think it would very well refer to parsing as well
(i.e. &amp;quot;Parsing changes focus on validation&amp;quot;);
the quote would still make sense.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://donnywinston.com/posts/shotgun-semantics/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Shotgun Semantics&lt;/em&gt; by Donny Winston&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;Developers often resort to &lt;em&gt;shotgun parsing&lt;/em&gt;: scattering data checks and fallback values in various places throughout the system's main logic.&lt;/p&gt;
&lt;p&gt;The habit of scattering parser-like behaviour throughout an application's code and the resulting inconsistencies in data handling can often lead not just to annoying complications and bugs, but also security vulnerabilities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://old.reddit.com/r/typescript/comments/vaukc1/has_your_team_adopted_typescript_how_is_it_going/ic4kzpx/&quot; class=&quot;link link-external&quot;&gt;a deleted user's comment on an /r/typescript post &lt;em&gt;Has your team adopted TypeScript? How is it going?&lt;/em&gt;&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;I joined a team 6 months ago that had recently adopted TypeScript to a fairly new (2 years old) project. [...]&lt;/p&gt;
&lt;p&gt;People didn't really know why they were using it. They would create interfaces for objects coming over APIs (good), but would make them have slightly differently named fields, like &lt;code&gt;mainId&lt;/code&gt; would be named &lt;code&gt;main_id&lt;/code&gt; in the interface (bad). This resulted in pointless chunks of code to &amp;quot;convert&amp;quot; the API object to the front-end interface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;A reply by monnef:
&lt;blockquote&gt;
&lt;p&gt;In some languages (like Haskell) this is the recommended approach – separate types for API and rest of the application. When the API changes, you don't have to change all code which works with the type, just the convert functions. Even in TS, I really don't like reusing API types (&lt;a href=&quot;https://gitlab.com/monnef/oats&quot; class=&quot;link link-external&quot;&gt;generated&lt;/a&gt; in our case) for forms and a few other places, because more often than not the types aren't actually the same (e.g. &lt;code&gt;null&lt;/code&gt; vs &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt; vs &lt;code&gt;string&lt;/code&gt; and so on).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Another reply by pm_me_ur_happy_traiI:
&lt;blockquote&gt;
&lt;p&gt;I actually encourage my team to do exactly this. Back-end APIs are optimized to be communicated over the wire. They need to be turned into something that works with front-end conventions and suits the needs of our app.&lt;/p&gt;
&lt;p&gt;We build our front-ends using data structures that make sense to the front-end, and there's usually a function to turn the back-end API response into that. The added upside is that if the back-end changes, we just need to fix the one function as opposed to renaming properties all over our code base.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://blog.theodo.com/2023/04/parsing-rest-api-responses-in-typescript-using-zod/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Parsing REST API Responses in TypeScript using Zod&lt;/em&gt; by Matt Newhall&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;The [&lt;em&gt;&amp;quot;parse, don't validate&amp;quot;&lt;/em&gt;] concept boils down to the underlying assumption in validation that a type can have valid and invalid instances. Let's take an example of validating a type, &lt;code&gt;T&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;validateType&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 constant&quot;&gt;T&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 builtin&quot;&gt;boolean&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, &lt;code&gt;validateType&lt;/code&gt; takes a type &lt;code&gt;T&lt;/code&gt; and then by evaluating it returns a boolean stating if the incoming object was a valid object of type &lt;code&gt;T&lt;/code&gt; or not. However, this means that invalid instances of &lt;code&gt;T&lt;/code&gt; can exist. Alternatively, using parsing:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;parseType&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 builtin&quot;&gt;unknown&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 constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Error
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can take some data of an unknown type, and check if this matches what is expected of type &lt;code&gt;T&lt;/code&gt;. From this, we can output a guaranteed type &lt;code&gt;T&lt;/code&gt;, or handle the error in the event that it is not. This makes the schema checking system more TypeScript-esque, making it more akin to a type guard than blindly assuming a variable's type.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;An interesting point that I hadn't considered:
&amp;quot;[Validating instead of parsing] means that invalid instances of &lt;code&gt;T&lt;/code&gt; can exist.&amp;quot;
On the other hand, shouldn't &lt;code&gt;validateType&lt;/code&gt; take an &lt;code&gt;unknown&lt;/code&gt; param, not a &lt;code&gt;T&lt;/code&gt; param? Hmm...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An excerpt from &lt;a href=&quot;https://eweise.com/post/sideeffects/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Pushing Side Effects to the Side&lt;/em&gt; by Eric Weise&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;Functional programming provides a treasure trove of useful patterns, one of which is pushing side effects to the edges of your application. Side effects are functions that have non-deterministic behavior. Examples include making an HTTP call or persisting data to the database. [...] By isolating these types of calls, we can more easily test our code. [...]&lt;/p&gt;
&lt;p&gt;How many methods could you turn into simple pure function calls simply by removing side effect calls such as repositories from your business logic? Most projects I have worked on just sprinkle database calls throughout service layer.&lt;/p&gt;
&lt;p&gt;In general the pattern I try to follow is;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retrieve all the data necessary to perform the business logic (side effect code).&lt;/li&gt;
&lt;li&gt;Perform the business logic using in-memory data (pure functions).&lt;/li&gt;
&lt;li&gt;Persist changes to the database (side effect code).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These three steps can't be followed every time but when they can, the code will be much easier to test.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;I think &amp;quot;pushing side effects to the side&amp;quot; doesn't benefit only testing,
so &amp;quot;the code will be much easier to test&amp;quot; could also read
&amp;quot;the code will be much &lt;em&gt;clearer overall&lt;/em&gt;.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Slogan of the &lt;a href=&quot;https://github.com/GervinFung/parse-dont-validate&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;parse-dont-validate&lt;/code&gt; TypeScript library&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;Validating data acts as a gatekeeper, parsing them into meaningful data types adds valuable information to raw data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/kwasniew/status/1426866923334250498&quot; class=&quot;link link-external&quot;&gt;A tweet by Mateusz Kwaśniewski: &lt;em&gt;Parse, don't validate – TypeScript edition&lt;/em&gt;&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Features Joi and Zod, which inspired me to use them in this blog post.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/colinhacks/zod/discussions/962&quot; class=&quot;link link-external&quot;&gt;A GitHub discussion under the Zod project: &lt;em&gt;Confusing terms – parse vs validate&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;changelog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#changelog&quot;&gt;Changelog&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2023-06-13: Blog post published&lt;/li&gt;
&lt;li&gt;2023-06-25: Added links to today's blog post
&lt;a href=&quot;/blog/date-objects-vs-date-strings/&quot; class=&quot;link&quot;&gt;&lt;em&gt;&lt;code&gt;Date&lt;/code&gt; objects are nicer to work with than date strings&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;The corresponding type of &lt;code&gt;Joi.string()&lt;/code&gt; would be &lt;code&gt;string | undefined&lt;/code&gt;,
because in Joi, all values are optional by default.
I find it a bit confusing.
The type of &lt;code&gt;Joi.string().required()&lt;/code&gt; would be &lt;code&gt;string&lt;/code&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;I wonder if there's ever a good reason for a parser to mutate the input data. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/epub-to-azw3/</id><title>Auto-converting EPUB files to AZW3 instead of MOBI in Calibre</title><link href="https://mtsknn.fi/blog/epub-to-azw3/" /><published>2023-04-29T12:00:00+03:00</published><updated>2023-04-29T12:00:00+03:00</updated><category term="Books"></category><content type="html">&lt;p&gt;MOBI is an old e-book format.
AZW3 is a newer and apparently better format;
for instance, it supports embedded fonts.
Here's how to configure Calibre to prefer the better format.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Global settings&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;In Calibre, go to Preferences → Behavior&lt;/li&gt;
&lt;li&gt;Change &amp;quot;Preferred output format&amp;quot; from MOBI to AZW3&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device settings&lt;/strong&gt; might override global settings,
so check device settings too
&lt;ol&gt;
&lt;li&gt;Plug in your device (via USB)&lt;/li&gt;
&lt;li&gt;In Calibre, select Device → Configure this device&lt;/li&gt;
&lt;li&gt;Under &amp;quot;Select available formats and their order for this device,&amp;quot;
move azw3 to the top
&lt;ul&gt;
&lt;li&gt;My old order was this:
&lt;ol&gt;
&lt;li&gt;azw&lt;/li&gt;
&lt;li&gt;mobi&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;azw3&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;So I moved azw3 to the top:
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;azw3&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;azw&lt;/li&gt;
&lt;li&gt;mobi&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/bye-acsm-and-drm/</id><title>De-ACSM'ing and de-DRM'ing e-books for fun (but not profit)</title><link href="https://mtsknn.fi/blog/bye-acsm-and-drm/" /><published>2023-04-28T12:00:00+03:00</published><updated>2023-04-29T12:00:00+03:00</updated><category term="Books"></category><content type="html">&lt;p&gt;A reminder for myself how to make library e-books pleasant to use
with the help of Calibre and two Calibre plugins.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My local library provides many e-books for free, which is great,
but actually getting those e-books to my Kindle Paperwhite is a hassle:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download an EPUB file (so the button says on the library site)
– whoops, it's actually an ACSM file.&lt;/li&gt;
&lt;li&gt;Download Adobe Digital Editions (ADE) software to open the ACSM file
– whoops, ADE requires an Adobe account.&lt;/li&gt;
&lt;li&gt;Create an Adobe account.&lt;/li&gt;
&lt;li&gt;Get an EPUB file from ADE.&lt;/li&gt;
&lt;li&gt;Upload the EPUB file to Kindle Paperwhite
– whoops, Kindle doesn't support EPUB files.&lt;/li&gt;
&lt;li&gt;Convert the EPUB file to a Kindle-supported format (e.g. MOBI)
– whoops, the EPUB file is DRM-protected so it's not that simple.&lt;/li&gt;
&lt;li&gt;Remove the DRM protection by using a shady website,
probably risking leaking your personal info (likely stored in the DRM-protected EPUB file).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Finally&lt;/em&gt; upload the DRM-free, Kindle-compatible file to Kindle.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I don't actually know the exact process
because I have never done it the &amp;quot;official way.&amp;quot;
Just too complicated, too much work, too annoying.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;initial-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#initial-setup&quot;&gt;Initial setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Needs to be done only once.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download and install &lt;a href=&quot;https://calibre-ebook.com/&quot; class=&quot;link link-external&quot;&gt;Calibre (e-book management software)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Download and install &lt;a href=&quot;https://github.com/noDRM/DeDRM_tools&quot; class=&quot;link link-external&quot;&gt;DeDRM_tools plugin for Calibre&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;This plugin will automatically remove DRM protection from EPUB files that you drag-and-drop to Calibre.&lt;/li&gt;
&lt;li&gt;noDRM's fork (linked to above) is up-to-date; the original is not.&lt;/li&gt;
&lt;li&gt;Be sure to install this before the next plugin,
or you might need to do one extra step manually when configuring the next plugin.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Download, install and configure &lt;a href=&quot;https://github.com/Leseratte10/acsm-calibre-plugin&quot; class=&quot;link link-external&quot;&gt;ACSM Input plugin for Calibre&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;This plugin will automatically convert ACSM files that you drag-and-drop to Calibre into EPUB files
&lt;ul&gt;
&lt;li&gt;No need for ADE (Adobe Digital Editions software).&lt;/li&gt;
&lt;li&gt;No need for an Adobe account because you can create an anonymous authorization in the plugin's settings.
&lt;ul&gt;
&lt;li&gt;Make sure to &lt;a href=&quot;https://github.com/Leseratte10/acsm-calibre-plugin/discussions/52&quot; class=&quot;link link-external&quot;&gt;back up the authorization data&lt;/a&gt;,
just in case.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;(Optional: &lt;a href=&quot;/blog/epub-to-azw3/&quot; class=&quot;link&quot;&gt;Configure Calibre to auto-convert EPUB files to AZW3 instead of MOBI&lt;/a&gt;.)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;e-book-to-kindle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#e-book-to-kindle&quot;&gt;E-book to Kindle&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Download an ACSM file from library site.&lt;/li&gt;
&lt;li&gt;Drag-and-drop the ACSM file to Calibre.&lt;/li&gt;
&lt;li&gt;Plug in Kindle to computer (via USB).&lt;/li&gt;
&lt;li&gt;Select the book in Calibre and click &amp;quot;Send to device.&amp;quot;&lt;/li&gt;
&lt;li&gt;Eject Kindle.&lt;/li&gt;
&lt;li&gt;Go read and enjoy the book!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All steps except the 2nd one are fluff,
so this is actually a one-step process
(just drag-and-drop to Calibre).
Nice and easy.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/tricky-email-aliases/</id><title>Sending (duplicate) emails to email aliases can be tricky</title><link href="https://mtsknn.fi/blog/tricky-email-aliases/" /><published>2023-04-21T12:00:00+03:00</published><updated>2023-04-21T12:00:00+03:00</updated><category term="JavaScript"></category><category term="SendGrid"></category><content type="html">&lt;p&gt;If you send a single email to a bunch of email addresses,
and some of the addresses are aliases,
i.e. they point to the same email inbox,
chances are high that only one copy of the email is delivered to that inbox.&lt;/p&gt;
&lt;h2 id=&quot;example-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-problem&quot;&gt;Example problem&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;I had five test users and one email alias per test user; e.g.:
&lt;ul&gt;
&lt;li&gt;Test user 1: &lt;code&gt;foo@example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Test user 2: &lt;code&gt;foo+test-user-2@example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Test user 3: &lt;code&gt;foo+test-user-3@example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Test user 4: &lt;code&gt;custom-alias-1@example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Test user 5: &lt;code&gt;custom-alias-2@example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;All five email addresses pointed to the same email inbox: &lt;code&gt;foo@example.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I sent a single email to those five addresses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I expected to receive five copies of the email to my email inbox, but I received only one copy.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;In some test runs I sometimes received two or maybe even three emails,
but never all five.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;test-users-vs-real-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#test-users-vs-real-users&quot;&gt;Test users vs real users&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In my case the users were test users,
making testing email delivery difficult
because only some test users received the emails.&lt;/p&gt;
&lt;p&gt;But the problem would affect real users too.
Example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Somebody has registered to a service multiple times,
each time using a different email alias.&lt;/li&gt;
&lt;li&gt;The service sends an email to all its users.&lt;/li&gt;
&lt;li&gt;That somebody should receive as many emails as they have users,
but (if this problem exists in that service) they might get only one email.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tangent-sendgrid&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#tangent-sendgrid&quot;&gt;Tangent: SendGrid&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I used the &lt;a href=&quot;https://github.com/sendgrid/sendgrid-nodejs/blob/v7.1.1/docs/use-cases/single-email-multiple-recipients.md&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;sendMultiple()&lt;/code&gt; method of the SendGrid Node.js API&lt;/a&gt;,
but that's tangential:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This isn't a JavaScript-specific problem.&lt;/li&gt;
&lt;li&gt;This isn't a SendGrid-specific problem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;This is a general problem of delivering multiple copies of an email to multiple email aliases.&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;The same problem would happen when sending a single email to multiple email aliases non-programmatically, e.g. directly from Gmail.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Still, I wanted to mention this because at first I thought that the problem was in SendGrid.&lt;/p&gt;
&lt;p&gt;SendGrid's Activity Feed displayed the &amp;quot;Delivered&amp;quot; status for all emails,
meaning that the receiving mail servers had successfully received the emails.
Indeed, the problem wasn't that SendGrid failed to send all the emails (it didn't fail);
the problem was that the receiving mail servers failed to deliver the duplicate emails to the inboxes.&lt;/p&gt;
&lt;h2 id=&quot;the-root-cause-identical-message-ids&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-root-cause-identical-message-ids&quot;&gt;The root cause: identical &lt;code&gt;Message-Id&lt;/code&gt;s&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Every email has a unique &lt;code&gt;Message-Id&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I asked Fastmail Support &amp;quot;Is the &lt;code&gt;Message-Id&lt;/code&gt; always created/determined by the sender?&amp;quot;
and they replied:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes, that's correct.
However, if the sender doesn't specify one, due to a bug, we will create one during email delivery.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All emails sent in a single batch share the same &lt;code&gt;Message-Id&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Most mail servers silently discard duplicate emails (based on &lt;code&gt;Message-Id&lt;/code&gt;).&lt;/strong&gt;
(But there's a precondition; keep on reading.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Based on my testing, this is true for at least these mail servers/providers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Exchange / Outlook&lt;/li&gt;
&lt;li&gt;Fastmail&lt;/li&gt;
&lt;li&gt;Gmail / Google Workspace (formerly G Suite)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For example,
&lt;a href=&quot;https://www.fastmail.help/hc/en-us/articles/360058753614-Why-messages-bounce-back&quot; class=&quot;link link-external&quot;&gt;Fastmail's &lt;em&gt;Why messages bounce back&lt;/em&gt; page&lt;/a&gt;
states the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Most messages have a unique identifier called the message ID.
When a message arrives at an account, the message ID is noted.
If a second message with the same ID arrives, it is ignored and silently discarded.
This is used to stop infinite mail loops overloading your account or our system.
However, it can result in odd behavior when the same message arrives from different sources, as only the first one will actually be delivered.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note the last sentence:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However, it can result in odd behavior when the same message arrives from different sources, as only the first one will actually be delivered.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Replacing &amp;quot;from different sources&amp;quot; with &amp;quot;to multiple email aliases&amp;quot; would keep the sentence correct and describe my problem better:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However, it can result in odd behavior when the same message arrives &lt;em&gt;to multiple email aliases&lt;/em&gt;, as only the first one will actually be delivered.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The solution is to &lt;strong&gt;send the emails sequentially (one at a time), e.g. at 1-second intervals&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;One way would be to make one API request per recipient,
but that would be slow and inefficient because there would be as many API requests as recipients.
(Then each email would probably have unique &lt;code&gt;Message-Id&lt;/code&gt;,
which alone would fix the problem.)&lt;/p&gt;
&lt;p&gt;Eventually I found a better way (I'm using SendGrid as mentioned above):
&lt;strong&gt;specifying different &lt;a href=&quot;https://github.com/sendgrid/sendgrid-nodejs/blob/v7.1.1/docs/use-cases/scheduled-send.md&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;sendAt&lt;/code&gt; values&lt;/a&gt; for each recipient&lt;/strong&gt;
makes SendGrid send the emails at different times,
but allows making as few API requests as possible.&lt;/p&gt;
&lt;p&gt;Curiously, the &lt;code&gt;Message-Id&lt;/code&gt; is still the same in every email,
but this still fixes the problem!
That's because the emails don't arrive simultaneously.
In other words (this is the precondition mentioned above):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Most mail servers seem to &lt;em&gt;not&lt;/em&gt; discard duplicate emails (based on &lt;code&gt;Message-Id&lt;/code&gt;) if the emails arrive at different times (not simultaneously).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have successfully tested this with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Exchange / Outlook&lt;/li&gt;
&lt;li&gt;Fastmail&lt;/li&gt;
&lt;li&gt;Gmail / Google Workspace (formerly G Suite)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fastmail Support confirmed this for their part:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So it seems we ignore duplicate emails delivered in a very short period (e.g. within a second).
These emails were delivered within a second apart which is why they were not filtered as duplicates.
This is expected behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#code&quot;&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using SendGrid:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; emails &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;'foo@example.com'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;'foo+test-user-2@example.com'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;'foo+test-user-3@example.com'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;'custom-alias-1@example.com'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;'custom-alias-2@example.com'&lt;/span&gt;&lt;span class=&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;// SendGrid expects a UNIX timestamp in seconds&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentTimeInMilliSeconds &lt;span class=&quot;token operator&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;now&lt;/span&gt;&lt;span class=&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; currentTimeInSeconds &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentTimeInMilliSeconds &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

sendGrid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendMultiple&lt;/span&gt;&lt;span class=&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;personalizations&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; emails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&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 comment&quot;&gt;// Send the emails at 1-second intervals&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// to ensure that delivery to email aliases works too.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Mail servers silently discard duplicate emails&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// that arrive to the same inbox at the same time,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// so multiple emails going to the same email inbox (via email aliases)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// need to be sent at different times.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Also add a few seconds just to be safe,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// i.e. to avoid sending the first few emails simultaneously.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// More info: https://mtsknn.fi/blog/tricky-email-aliases/&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sendAt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentTimeInSeconds &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&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 literal-property property&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      sendAt&lt;span class=&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;subject&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Test email'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'&amp;lt;p&gt;Email body&amp;lt;/p&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;caveat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#caveat&quot;&gt;Caveat&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This fix/hack will make some recipients receive the email after a small delay.&lt;/p&gt;
&lt;p&gt;If you have 1,000 recipients and send the emails at 1-second intervals,
the last recipient will receive the email after about 1,000 seconds ≈ 17 minutes.
In my case that's totally OK.&lt;/p&gt;
&lt;p&gt;If that's too long,
you could send the emails in smaller batches.&lt;/p&gt;
&lt;p&gt;The maximum is anyway 1,000 recipients per one SendGrid API request.
From &lt;a href=&quot;https://docs.sendgrid.com/for-developers/sending-email/personalizations&quot; class=&quot;link link-external&quot;&gt;SendGrid's &lt;em&gt;Personalizations&lt;/em&gt; page&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may not include more than 1000 personalizations per API request.
If you need to include more than 1000 personalizations, please divide these across multiple API requests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;tangent-24-hours&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#tangent-24-hours&quot;&gt;Tangent: −24 hours&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I stated two things above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most mail servers silently discard duplicate emails (based on &lt;code&gt;Message-Id&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Most mail servers seem to &lt;em&gt;not&lt;/em&gt; discard duplicate emails (based on &lt;code&gt;Message-Id&lt;/code&gt;)
if the emails arrive at different times (not simultaneously).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a test,
I scheduled the emails to be sent at 1-second intervals like before,
but also &lt;strong&gt;24 hours in the past&lt;/strong&gt;.
Like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;sendGrid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendMultiple&lt;/span&gt;&lt;span class=&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;personalizations&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; emails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&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 comment&quot;&gt;// ⚠️ Example, don't actually do this&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; twentyFourHoursInSeconds &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sendAt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentTimeInSeconds &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; twentyFourHoursInSeconds

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      sendAt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; email&lt;span class=&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;// ...&lt;/span&gt;
&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;I successfully received all emails – confusing!&lt;/p&gt;
&lt;p&gt;I asked about this from Fastmail Support:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The timestamps in the Date headers are a second apart like expected;
but the timestamps in the Received headers are exactly the same.&lt;/p&gt;
&lt;p&gt;Doesn't this mean that SendGrid sent the five emails at the same time?
I would expect SendGrid to do that because the Date headers were 24 hours in the past,
but I can't know for sure.&lt;/p&gt;
&lt;p&gt;And don't the identical Received timestamps also mean that
you received all emails at the same time?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Their reply:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It's based on the received time at our end.
Looking at the logs I can see that these emails came in almost within a second.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2022-11-06T23:30:33.991668-05:00 mx2 (info) postfix-mx/cleanup[630908]: F1DBE6A017A: message-id=&amp;lt;a7ZrAF9NQbeVa12gUVIbRd@geopod-ismtpd-3-1&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2022-11-06T23:30:33.992920-05:00 mx3 (info) postfix-mx/cleanup[725605]: F22DB1960153: message-id=&amp;lt;a7ZrAF9NQbeVa12gUVIbRd@geopod-ismtpd-3-1&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2022-11-06T23:30:34.039558-05:00 mx1 (info) postfix-mx/cleanup[774312]: 097E023C00C6: message-id=&amp;lt;a7ZrAF9NQbeVa12gUVIbRd@geopod-ismtpd-3-1&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2022-11-06T23:30:34.066426-05:00 mx3 (info) postfix-mx/cleanup[725548]: 100301960158: message-id=&amp;lt;a7ZrAF9NQbeVa12gUVIbRd@geopod-ismtpd-3-1&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2022-11-06T23:30:34.291125-05:00 mx1 (info) postfix-mx/cleanup[774312]: 46EA223C0074: message-id=&amp;lt;a7ZrAF9NQbeVa12gUVIbRd@geopod-ismtpd-3-1&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, they were not discarded as duplicates.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, SendGrid sent the emails at slightly different times
even though they were scheduled to be sent 24 hours ago.
Or at least Fastmail received them at slightly different times.&lt;/p&gt;
&lt;p&gt;I wouldn't rely on this behavior,
so &lt;strong&gt;I don't recommend this approach (scheduling the emails to be sent in the past)&lt;/strong&gt;,
but this is interesting to know nonetheless.&lt;/p&gt;
&lt;h3 id=&quot;non-solutions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#non-solutions&quot;&gt;Non-solutions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I tried these two things that didn't work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sendgrid/sendgrid-nodejs/blob/v7.1.1/docs/use-cases/custom-headers.md&quot; class=&quot;link link-external&quot;&gt;Custom headers&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;sendgrid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendMultiple&lt;/span&gt;&lt;span class=&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;personalizations&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; emails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;headers&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-property property&quot;&gt;'X-EmailBatchId'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;index &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 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;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sendgrid/sendgrid-nodejs/blob/main/docs/use-cases/customization.md&quot; class=&quot;link link-external&quot;&gt;Custom subject per recipient&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;sendgrid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendMultiple&lt;/span&gt;&lt;span class=&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;personalizations&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; emails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token literal-property property&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Email &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;index &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 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 comment&quot;&gt;// or&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;dynamicTemplateData&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;subject&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Email &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;index &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 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;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;rant-sendgrid-support-was-meh&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#rant-sendgrid-support-was-meh&quot;&gt;Rant: SendGrid Support was meh&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SendGrid Support couldn't help me solve this problem.&lt;/p&gt;
&lt;p&gt;That's kind of okay because this is quite an obscure thing and not specific to SendGrid;
on the other hand, I'd expect an email delivery service provider to have great knowledge about even the most obscure things related to delivering emails.&lt;/p&gt;
&lt;p&gt;What's worse is that
one of their &amp;quot;Senior Technical Support Engineers&amp;quot; even said something factually incorrect:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I believe the root of the issue here is that multiple recipients require multiple requests, &lt;em&gt;unless&lt;/em&gt; you're including them as CC or BCC.
At some point in 2021, our system began no longer accepting multiple &amp;quot;TO&amp;quot; recipients within one request.
Whereas previously, you could have 1 request with multiple recipients listed in the TO portion.
Now, to send 1 email to 10 recipients individually, this requires 10 individual requests.&lt;/p&gt;
&lt;p&gt;I suggest that you and your team look into adjusting your system's workflow so that such situations result in multiple requests, rather than using &amp;quot;sendmultiple&amp;quot; within 1 request.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don't understand that reply
as it's simply false that you can't send an email to multiple recipients with a single request.&lt;/p&gt;
&lt;p&gt;The SendGrid docs have a section
&lt;a href=&quot;https://docs.sendgrid.com/for-developers/sending-email/personalizations#sending-the-same-email-to-multiple-recipients&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Sending the same email to multiple recipients&lt;/em&gt;&lt;/a&gt;.
At the top of the page,
it's mentioned that you can send an email to max 1,000 recipients with a single request.
That's much better and faster than doing 1,000 individual requests.&lt;/p&gt;
&lt;p&gt;Plus I had already succeeded at sending an email to multiple recipients with a single request;
I was just having problems with email aliases / duplicate emails.&lt;/p&gt;
&lt;h2 id=&quot;praise-fastmail-support-is-great&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#praise-fastmail-support-is-great&quot;&gt;Praise: Fastmail Support is great&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fastmail Support was very helpful in helping me solve and understand the problem.&lt;/p&gt;
&lt;p&gt;They have been helpful in the past too,
when I have had email problems.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/mirror-of-erised/</id><title>Harry Potter, the Mirror of Erised, and mindless internet surfing</title><link href="https://mtsknn.fi/blog/mirror-of-erised/" /><published>2023-04-14T12:00:00+03:00</published><updated>2023-04-14T12:00:00+03:00</updated><category term="Books"></category><category term="NoSurf"></category><content type="html">&lt;p&gt;Mindlessly surfing the internet
is like staring at the Mirror of Erised from the Harry Potter books.
(Minor Harry Potter spoilers ahead.)&lt;/p&gt;
&lt;h2 id=&quot;mindless-surfing-vs-the-mirror-of-erised&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#mindless-surfing-vs-the-mirror-of-erised&quot;&gt;Mindless surfing vs the Mirror of Erised&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hanki.dev/&quot; class=&quot;link link-external&quot;&gt;My bro&lt;/a&gt; shared me &lt;a href=&quot;https://old.reddit.com/r/nosurf/comments/11p5mzo/mindless_surfing_is_like_the_mirror_of_erised_in/&quot; class=&quot;link link-external&quot;&gt;a Reddit post on /r/nosurf&lt;/a&gt; the other day.&lt;/p&gt;
&lt;p&gt;Here's the full post (with a few typos fixed):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mindless surfing is like the Mirror of Erised in Harry Potter&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For those of you who haven't read Harry Potter,
the Mirror of Erised is a mirror which shows the deepest desires of a person.
In the story, Harry finds the mirror and sees his parents in it.
He keeps returning every day until Dumbledore gently tells him to stop doing so.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This mirror will give us neither knowledge or truth.
Men have wasted away before it, entranced by what they have seen, or been driven mad, not knowing if what it shows is real or even possible.
It does not do well to dwell on dreams and forget to live.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a great parallel to mindless internet surfing.
We watch our deepest desires on the internet like being rich, falling in love, living a certain lifestyle or even being in another country.
I've spent a lot of time browsing nice apartment pics, vlogs, or even street view of nice cities where I wanna live, not because of curiosity or exploration but because of a desire to see my dream.
This is actually preventing me from living fully and actually working to achieve my dreams in the first place.&lt;/p&gt;
&lt;p&gt;I just found it interesting how similar the two of these are.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;longer-harry-potter-quote&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#longer-harry-potter-quote&quot;&gt;Longer Harry Potter quote&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recently started reading the Harry Potter books for the first time.&lt;/p&gt;
&lt;p&gt;The first book,
&lt;em&gt;Harry Potter and the Philosopher's Stone&lt;/em&gt;,
has 332 pages (Bloomsbury, 2014 edition),
but I read it in just 5 days.
It was that good!&lt;/p&gt;
&lt;p&gt;The first book also introduces the Mirror of Erised.
From pages 229–230:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;'Let me explain.
The happiest man on earth would be able to use the Mirror of Erised like a normal mirror,
that is, he would look into it and see himself exactly as he is.
Does that help?'&lt;/p&gt;
&lt;p&gt;Harry thought.
Then he said slowly,
'It shows us what we want … whatever we want …'&lt;/p&gt;
&lt;p&gt;'Yes and no', said Dumbledore quietly.
'It shows us nothing more or less than the deepest, most desperate desire of our hearts.
You, who have never known your family, see them standing around you.
Ronald Weasley, who has always been overshadowed by his brothers, sees himself standing alone, the best of all of them.
However, this mirror will give us neither knowledge or truth.
Men have wasted away before it, entranced by what they have seen, or been driven mad, not knowing if what it shows is real or even possible.&lt;/p&gt;
&lt;p&gt;'The Mirror will be moved to a new home tomorrow, Harry, and I ask you not to go looking for it again.
If you ever &lt;em&gt;do&lt;/em&gt; run across it, you will now be prepared.
It does not do to dwell on dreams and forget to live, remember that.
Now, why don't you put that admirable Cloak back on and get off to bed?'&lt;/p&gt;
&lt;p&gt;Harry stood up.&lt;/p&gt;
&lt;p&gt;'Sir – Professor Dumbledore? Can I ask you something?'&lt;/p&gt;
&lt;p&gt;'Obviously, you've just done so,' Dumbledore smiled. 'You may ask me one more thing, however.'&lt;/p&gt;
&lt;p&gt;'What do you see when you look in the Mirror?'&lt;/p&gt;
&lt;p&gt;'I? I see myself holding a pair of thick, woollen socks.'&lt;/p&gt;
&lt;p&gt;Harry stared.&lt;/p&gt;
&lt;p&gt;'One can never have enough socks,' said Dumbledore.
'Another Christmas has come and gone and I didn't get a single pair.
People will insist on giving me books.'&lt;/p&gt;
&lt;p&gt;It was only when he was back in bed that it struck Harry that Dumbledore might not have been quite truthful.
But then, he thought, as he shoved Scabbers off his pillow, it had been quite a personal question.&lt;/p&gt;
&lt;/blockquote&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/agile-process-visualized/</id><title>Video notes: Agile Product Ownership in a Nutshell</title><link href="https://mtsknn.fi/blog/agile-process-visualized/" /><published>2023-04-11T12:00:00+03:00</published><updated>2023-04-11T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;This 16-minute video by Henrik Kniberg
is a great overview of the agile software development process,
but also contains lots of smaller great insights.&lt;/p&gt;
&lt;h2 id=&quot;the-video&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-video&quot;&gt;The video&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=502ILHjX9EE&quot; class=&quot;link link-external&quot;&gt;Watch &lt;em&gt;Agile Product Ownership in a Nutshell&lt;/em&gt; (15:51) on YouTube.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I found the video
via &lt;a href=&quot;https://critter.blog/2023/04/06/pull-vs-push-visualized/&quot; class=&quot;link link-external&quot;&gt;Critter's blog post &lt;em&gt;Pull methodology, flow time, and WIP limits: visualized&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;top-3-moments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#top-3-moments&quot;&gt;Top 3 moments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The 16-minute video is packed with great insights.
I guess different things would stand out when rewatching the video later;
this time these three things resonated with me the most.&lt;/p&gt;
&lt;h3 id=&quot;knowledge-focus-vs-customer-value-focus-812-916&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#knowledge-focus-vs-customer-value-focus-812-916&quot;&gt;Knowledge focus vs customer value focus (8:12–9:16)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;./value-graph.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Knowledge can be seen as the opposite of risk, so when uncertainty is high, our focus is [on] knowledge acquisition; we focus on things like UI prototypes and technical spikes/experiments. Maybe not too exciting for the customers [(stakeholders)], but still valuable because we are reducing risk. From a customer value perspective, the curve [of customer value (y-axis) and time (x-axis)] looks [flat] in the beginning.&lt;/p&gt;
&lt;p&gt;As uncertainty is reduced, we gradually focus more and more on customer value; we know what we are going to build and how, so just do it. And by doing the highest-value [user] stories first, we get this nice steep value curve.&lt;/p&gt;
&lt;p&gt;And then gradually the value curve starts flattening out. We have built the most important stuff, and now we are just adding the bonus features; the toppings of an ice cream. This is a nice place to be [in] because at any point [the Product Owner] and the team may decide to &amp;quot;trim the tail,&amp;quot; to cut right here and move on to another more important project. Or maybe start a whole new feature area within the same product. That is business agility.&lt;/p&gt;
&lt;p&gt;So when I talk about value [of user stories], I actually mean knowledge value + customer value. And we need to continuously find the trade-off between these two.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;correct-vs-good-vs-fast-939-1042&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#correct-vs-good-vs-fast-939-1042&quot;&gt;Correct vs good vs fast (9:39–10:42)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;./correct-good-fast.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Should we focus on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;building the right thing&lt;/li&gt;
&lt;li&gt;or building the thing right&lt;/li&gt;
&lt;li&gt;or perhaps building it fast?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideally we want all three, but it's hard to find the balance.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Product owners tend to focus on building the right thing.&lt;/li&gt;
&lt;li&gt;Development teams tend to focus on building the thing right.&lt;/li&gt;
&lt;li&gt;Scrum masters or agile coaches tend to focus on shortening the feedback loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Speed is actually worth emphasizing&lt;/strong&gt; because a short feedback loop will accelerate learning, so you'll more quickly learn what the right thing is and how to build it right.&lt;/p&gt;
&lt;p&gt;However, all three aspects are important, so keep trying to find the balance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;reducing-scope-vs-extending-time-1315-1400&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#reducing-scope-vs-extending-time-1315-1400&quot;&gt;Reducing scope vs extending time (13:15–14:00)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;./cut-scope-vs-extend-time.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Suppose a stakeholder says: &amp;quot;Can we get these features by Christmas?&amp;quot; Now, that's a fixed time, fixed scope question.&lt;/p&gt;
&lt;p&gt;Looking at trend lines, [the Product Owner] says: &amp;quot;Nope, sorry, ain't gonna happen,&amp;quot; followed by, &amp;quot;here's how much we can get done by Christmas&amp;quot; or &amp;quot;here's how much more time we would need to get everything done.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It's generally better to reduce scope than to extend time,&lt;/strong&gt; because if we reduce scope first, we still have the option to extend the time later and add the rest of the [user] stories.&lt;/p&gt;
&lt;p&gt;Vice versa doesn't work because, darn it, we can't turn the clock backwards. [...]&lt;/p&gt;
&lt;p&gt;So, [the Product Owner] puts it this way: &amp;quot;We could deliver something [soon] and the rest later, or we could deliver nothing [soon] and the rest later; which do you prefer?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/atomic-habits/</id><title>Book notes: Atomic Habits</title><link href="https://mtsknn.fi/blog/atomic-habits/" /><published>2023-04-07T12:00:00+03:00</published><updated>2023-04-07T12:00:00+03:00</updated><category term="Books"></category><content type="html">&lt;p&gt;Tiny good things accumulate into great things.
Tiny bad things accumulate into horrible things.
This book tells you how to do more of those good things
and less of those bad things.&lt;/p&gt;
&lt;h2 id=&quot;about-the-book&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#about-the-book&quot;&gt;About the book&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;People do things out of habit all the time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Atomic Habits&lt;/em&gt; tells you how to make good habits easy and effortless,
and how to make bad habits difficult and unattractive.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jamesclear.com/atomic-habits&quot; class=&quot;link link-external&quot;&gt;Read more about &lt;em&gt;Atomic Habits&lt;/em&gt; on James Clear's website&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#thoughts&quot;&gt;Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I read this book in January 2023.
This was the first book I read in a very long time (a few years maybe).&lt;/p&gt;
&lt;p&gt;The book was great:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interesting topic&lt;/li&gt;
&lt;li&gt;Well written; not boring at all&lt;/li&gt;
&lt;li&gt;Many examples and anecdotes&lt;/li&gt;
&lt;li&gt;A good balance between theory and practical tips &amp;amp; tricks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found the book to be a nice general overview of human behavior:
why people do certain things (good or bad)
and why people don't do certain things (good or bad).
So the book isn't just about productivity.&lt;/p&gt;
&lt;h2 id=&quot;notes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#notes&quot;&gt;Notes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are the things that resonated with me the most.&lt;/p&gt;
&lt;p&gt;I wrote these originally on post-it notes in January 2023.
Now, almost 3 months later, I'm having difficulties understanding some of the post-its,
so the notes below are partly confusing. 🙈&lt;/p&gt;
&lt;h3 id=&quot;how-to-do-a-habit-more&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-to-do-a-habit-more&quot;&gt;How to do a habit more&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Make it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Obvious&lt;/li&gt;
&lt;li&gt;Attractive&lt;/li&gt;
&lt;li&gt;Easy&lt;/li&gt;
&lt;li&gt;Satisfying&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(Note to self: examples would be nice...)&lt;/p&gt;
&lt;h3 id=&quot;how-to-ditch-a-bad-habit&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-to-ditch-a-bad-habit&quot;&gt;How to ditch a bad habit&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Make it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Invisible (out of sight, out of mind)&lt;/li&gt;
&lt;li&gt;Unattractive&lt;/li&gt;
&lt;li&gt;Difficult&lt;/li&gt;
&lt;li&gt;Unsatisfying&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;the-1percent-rule&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-1percent-rule&quot;&gt;The 1% rule&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Getting 1% better at something (or improving something by 1%) every day for one year
yields great dividends in the long run
&lt;ul&gt;
&lt;li&gt;1.01³⁶⁵ ≈ 37.78&lt;/li&gt;
&lt;li&gt;Progress is slow but exponential/compounding&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conversely: regressing 1% at something every day for one year destroys the original value
&lt;ul&gt;
&lt;li&gt;0.99³⁶⁵ ≈ 0.0255&lt;/li&gt;
&lt;li&gt;So bad habits, stress and negative thoughts compound too!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;focus-on-processes-not-goals&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#focus-on-processes-not-goals&quot;&gt;Focus on processes, not goals&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Focusing on a process is living in the moment;
focusing on a goal is living in the future&lt;/li&gt;
&lt;li&gt;Enjoy what you are doing; treat goals as a bonus&lt;/li&gt;
&lt;li&gt;Achieving a goal is a momentary change
&lt;ul&gt;
&lt;li&gt;Focusing on a goal can feel discouraging and like nothing is happening&lt;/li&gt;
&lt;li&gt;Missing a goal can feel like failure even if you have made good progress&lt;/li&gt;
&lt;li&gt;Example: Melting an ice cube
&lt;ul&gt;
&lt;li&gt;Rising the temperature from −30 °C to −1 °C
looks like it doesn't do anything to an ice cube&lt;/li&gt;
&lt;li&gt;Finally rising the temperature one or two degrees more melts the ice cube&lt;/li&gt;
&lt;li&gt;The &amp;quot;trick&amp;quot; wasn't to rise the temperature only one or two degrees –
it was to rise it all those 30+ degrees&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Example: Stonemasonry
&lt;ul&gt;
&lt;li&gt;A stonemason might hit the same spot 99 times,
and it might look the hitting doesn't do anything&lt;/li&gt;
&lt;li&gt;Finally the 100th hit makes the rock to chip off&lt;/li&gt;
&lt;li&gt;All 100 hits were required even though 99% of them looked like they did nothing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;1-task-per-day&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#1-task-per-day&quot;&gt;1 task per day&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Do one task per day, and you have done 365 tasks at the end of the year.&lt;/li&gt;
&lt;li&gt;Otherwise you'll have 365+ pending tasks at the end of the year!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(I don't remember if the book had this kind of example
or whether this was my own though based on something else. 🤔)&lt;/p&gt;
&lt;h3 id=&quot;become-your-ideal-person&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#become-your-ideal-person&quot;&gt;Become your ideal person&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Decide who you want to be(come).&lt;/li&gt;
&lt;li&gt;Prove it to yourself with small wins.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;→ It's not about the goals but the system/process and identities.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Habits shape identities.&lt;/li&gt;
&lt;li&gt;Identities cause habits.&lt;/li&gt;
&lt;li&gt;Family &amp;amp; friends, tribe (neighborhood, nationality etc.) and the powerful&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(I'm not sure what the notes in this chapter mean. 🫣 Shitty notes.)&lt;/p&gt;
&lt;h3 id=&quot;habits-free-up-mental-juice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#habits-free-up-mental-juice&quot;&gt;Habits free up mental juice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Build habits to free up mental space (conscious brain juice) for other things.&lt;/li&gt;
&lt;li&gt;For example: it's great to not have to always think about what to eat or when to exercise etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;pointing-and-calling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pointing-and-calling&quot;&gt;Pointing-and-Calling&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Pointing at things makes your thoughts more conscious.&lt;/li&gt;
&lt;li&gt;Saying things aloud makes your thoughts more conscious.&lt;/li&gt;
&lt;li&gt;Combine pointing and saying aloud for the best effect (&amp;quot;Pointing-and-Calling&amp;quot;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;aside-baseball-bats&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#aside-baseball-bats&quot;&gt;Aside: baseball bats&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the intro chapter,
James Clear tells how he was once hit in the face by a flying baseball bat.&lt;/p&gt;
&lt;p&gt;His skull fractured and brains swelled etc.,
causing him to almost die.&lt;/p&gt;
&lt;p&gt;That's completely different what some movies and TV series portray.
Sometimes a guy is hit dozens of times with a (metallic!) baseball bat,
even to the head,
and all it does is make the guy groan a little.
Ridiculous.
(I had been shaking my head at this stupidity before reading the book;
James's anecdote just confirmed my hunch that even a single hit could be fatal.)&lt;/p&gt;
&lt;h2 id=&quot;verdict&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#verdict&quot;&gt;Verdict&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Atomic Habits&lt;/em&gt; is a great book, go read it!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/small-monitor-best/</id><title>From a super ultrawide monitor to a regular 16:9 monitor</title><link href="https://mtsknn.fi/blog/small-monitor-best/" /><published>2023-03-23T12:00:00+03:00</published><updated>2023-05-12T12:00:00+03:00</updated><category term="Battlestation"></category><content type="html">&lt;p&gt;After 2.5 years of using a 120 cm wide super ultrawide computer monitor with a 32:9 aspect ratio,
I'm back to a boring 64 cm wide 16:9 monitor.
The smaller monitor now feels better in every regard.&lt;/p&gt;
&lt;h2 id=&quot;super-ultrawide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#super-ultrawide&quot;&gt;Super ultrawide&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I bought &lt;a href=&quot;https://www.samsung.com/us/computing/monitors/gaming/49-crg9-dual-qhd-curved-qled-gaming-monitor-lc49rg90ssnxza/&quot; class=&quot;link link-external&quot;&gt;Samsung CRG9&lt;/a&gt;
in July 2020 for 950 € (sale price).
Some specs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;49&amp;quot;, 120 cm wide&lt;/li&gt;
&lt;li&gt;5120×1440 pixels (Dual QHD)&lt;/li&gt;
&lt;li&gt;120 Hz&lt;/li&gt;
&lt;li&gt;Curved VA panel&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;nice-its-wide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#nice-its-wide&quot;&gt;Nice: it's wide&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I wanted to try a super ultrawide monitor
because the wider the screen, the more windows can fit on it side by side.&lt;/p&gt;
&lt;p&gt;I thought that would be useful,
and it kind of is.
Having VS Code, Terminal and Firefox side by side can be nifty
when coding web apps.&lt;/p&gt;
&lt;h3 id=&quot;drawback-distractions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#drawback-distractions&quot;&gt;Drawback: distractions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On the other hand,
having more than one thing open at the same time can be distracting.
At least subconsciously.&lt;/p&gt;
&lt;p&gt;I hadn't considered this until I read
Alexey Guzey's blog post &lt;a href=&quot;https://guzey.com/2022-lessons/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;My 2022 self (I don't know them) was very wrong about meditation, huge monitors, and... sleep&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://guzey.com/2022-lessons/#the-more-the-bigger-monitors-the-better---a-single-16-laptop-monitor-is-perfect&quot; class=&quot;link link-external&quot;&gt;In chapter 4, Alexey tells&lt;/a&gt;
that he changed from his 4-monitor setup (49&amp;quot; + 34&amp;quot; + 24&amp;quot; + 16&amp;quot;)
to using just his 16&amp;quot; MacBook.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'm actually distracted by [having] my task list, calendar, notes, etc. always visible.&lt;/p&gt;
&lt;p&gt;[Now] I work on my 16&amp;quot; MacBook and do one thing at a time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So: one or max two windows open at a time = more focus.&lt;/p&gt;
&lt;h3 id=&quot;other-drawbacks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#other-drawbacks&quot;&gt;Other drawbacks&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The super ultrawide monitor is annoyingly wide,
so I had to turn my head quite a bit to look at the sides.&lt;/li&gt;
&lt;li&gt;The monitor is very heavy and thus difficult to move around.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/my-new-microphone-rode-procaster/&quot; class=&quot;link&quot;&gt;My microphone&lt;/a&gt;
blocked about a third of the monitor when in voice calls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you play video games (I play only rarely):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some games put certain UI elements in the corners,
so they are way too far away from the center where the action usually happens.
E.g. the minimap in Battlefield 4.&lt;/li&gt;
&lt;li&gt;In some games dual QHD can theoretically be more taxing for the GPU than 4K
even though dual QHD has less total pixels than 4K (7 372 800 vs 8 294 400).
That's because in many games there's more heavy stuff to
render horizontally (e.g. other players etc.)
than vertically (e.g. mostly sky and clouds).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;testing-smaller-resolutions-with-a-software&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#testing-smaller-resolutions-with-a-software&quot;&gt;Testing smaller resolutions with a software&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before changing to a smaller monitor,
I &amp;quot;converted&amp;quot; my super ultrawide monitor to a smaller monitor.&lt;/p&gt;
&lt;p&gt;I found &lt;a href=&quot;https://www.madrau.com/&quot; class=&quot;link link-external&quot;&gt;SwitchResX for Mac&lt;/a&gt; to be great:
it allowed me to apply black bars to the sides of my monitor.&lt;/p&gt;
&lt;p&gt;First I tried regular ultrawide resolution (3440×1440, WQHD, 43:18) for a couple of days.
Definitely better!
Less looking too far to the sides.&lt;/p&gt;
&lt;p&gt;The regular ultrawide resolution started to quickly feel still too wide.
Then I reduced the resolution to 2560×1440 (2K, 16:9).
Perfect aspect ratio!&lt;/p&gt;
&lt;p&gt;(16:10 could also work,
but there aren't many external monitors available with that aspect ratio.)&lt;/p&gt;
&lt;h2 id=&quot;back-to-169&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#back-to-169&quot;&gt;Back to 16:9&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I had bought &lt;a href=&quot;https://www.benq.eu/en-eu/business/monitor/bl2711u.html&quot; class=&quot;link link-external&quot;&gt;BenQ BL2711U&lt;/a&gt; in November 2017
but had never sold it,
so I already had a great monitor lying around.
The perks of procrastination.&lt;/p&gt;
&lt;p&gt;Some specs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;27&amp;quot;, 64 cm wide&lt;/li&gt;
&lt;li&gt;3840×2160 pixels (4K)&lt;/li&gt;
&lt;li&gt;60 Hz&lt;/li&gt;
&lt;li&gt;Flat (non-curved) IPS panel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now I have less horizontal pixels (3840 vs 5120)
but that's okay because
it's why I wanted to change to a smaller monitor in the first place.&lt;/p&gt;
&lt;p&gt;Two windows side by side, both taking 50% width, feels actually quite good now.
On the other hand,
placing two windows side by side on an ultrawide makes both windows a bit too wide.&lt;/p&gt;
&lt;p&gt;As a bonus I have more vertical pixels (2160 vs 1440)
and a nice IPS panel.&lt;/p&gt;
&lt;h3 id=&quot;27-vs-32&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#27-vs-32&quot;&gt;27&amp;quot; vs 32&amp;quot;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This 27&amp;quot; monitor feels perfect.
Not too small, not too big.&lt;/p&gt;
&lt;p&gt;A 32&amp;quot; monitor would probably be a little too big for my taste.
I would again have to start turning my head around too much
when looking at the sides.
And either the bottom side of the screen would be too low,
or the top side would be too high.&lt;/p&gt;
&lt;h2 id=&quot;meme&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#meme&quot;&gt;Meme&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I'll conclude this post with this nice meme
(idea by &lt;a href=&quot;https://hanki.dev/&quot; class=&quot;link link-external&quot;&gt;my bro&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./meme.jpg&quot; alt=&quot;The &amp;quot;IQ Bell Curve / Midwit&amp;quot; meme with the low IQ and high IQ persons saying &amp;quot;I use only one monitor&amp;quot; and the midwit person saying &amp;quot;Need ultrawide or 3+ monitors!&amp;quot;&quot;&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/bye-weekly-log/</id><title>I wrote a weekly log for half a year and it was stressful</title><link href="https://mtsknn.fi/blog/bye-weekly-log/" /><published>2023-03-17T12:00:00+03:00</published><updated>2023-03-17T12:00:00+03:00</updated><category term="Blogging"></category><content type="html">&lt;p&gt;&amp;quot;Weekly log&amp;quot; basically meaning weekly blog posts with a specific structure.
Today I removed the whole Weekly log.&lt;/p&gt;
&lt;h2 id=&quot;why-i-started-a-weekly-log&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-i-started-a-weekly-log&quot;&gt;Why I started a weekly log&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I started the weekly log
to reduce stress:
by publishing short weekly log entries,
I wouldn't need to stress so much about my blog.&lt;/p&gt;
&lt;p&gt;Writing blog posts takes time,
and I wanted to publish something regularly.&lt;/p&gt;
&lt;p&gt;And I did publish regularly:
I published the first entry on the first week of 2021
and then a new entry each week for 6 months
for a total of 26 entries.&lt;/p&gt;
&lt;h2 id=&quot;why-i-ditched-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-i-ditched-it&quot;&gt;Why I ditched it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So I wanted to reduce stress,
but here's what actually happened:
I had two things to maintain;
the blog and the weekly log.&lt;/p&gt;
&lt;p&gt;Or actually three,
because &lt;a href=&quot;/blog/goodbye-cookbook-hello-more-blog-posts/&quot; class=&quot;link&quot;&gt;this site used to also have a Cookbook section with &amp;quot;technical recipes.&amp;quot;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Publishing every week was nice for a while,
but quickly started to feel like work.
Having an obligation like that was stressful.&lt;/p&gt;
&lt;p&gt;Plus I didn't manage to write short and quick weekly log entries,
so it wasn't much easier or more enjoyable than writing blog posts.&lt;/p&gt;
&lt;h2 id=&quot;how-i-ditched-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-i-ditched-it&quot;&gt;How I ditched it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I moved the best bits to individual blog posts
and deleted the rest (unnecessary ramblings etc.).
I did this slowly, so looks like it took me almost two years.&lt;/p&gt;
&lt;h2 id=&quot;other-issues&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#other-issues&quot;&gt;Other issues&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;bad-discoverability-and-seo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bad-discoverability-and-seo&quot;&gt;Bad discoverability and SEO&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;(SEO = search engine optimization)&lt;/p&gt;
&lt;p&gt;The weekly log entries were on a separate &amp;quot;Weekly log&amp;quot; page.
Someone going through my blog posts might miss entirely that the &amp;quot;Weekly log&amp;quot; page has more blog-like stuff.&lt;/p&gt;
&lt;p&gt;Opening a weekly log entry was not a nice experience either
because the page was long and had lots of mixed content to go through.&lt;/p&gt;
&lt;p&gt;The weekly log entries appeared on Google with names like &amp;quot;22nd week of 2021 – Weekly log.&amp;quot;
Such titles aren't very clear nor inviting.&lt;/p&gt;
&lt;p&gt;So it wasn't easy to discover what topics the weekly log entries actually cover.&lt;/p&gt;
&lt;h3 id=&quot;too-rigid-structure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#too-rigid-structure&quot;&gt;Too rigid structure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;My weekly log was mainly inspired by &lt;a href=&quot;https://samselikoff.com/work-journal&quot; class=&quot;link link-external&quot;&gt;Sam Selikoff's Work journal&lt;/a&gt;
in which he publishes weekly bullet points
about work-related stuff, learnings and interesting stuff.&lt;/p&gt;
&lt;p&gt;Piggybacking Sam's Work journal,
I structured my weekly log entries around these four headings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;👨‍💼 Work&lt;/li&gt;
&lt;li&gt;👨‍🚀 Personal&lt;/li&gt;
&lt;li&gt;👨‍🎓 Learnings&lt;/li&gt;
&lt;li&gt;🕵️‍♂️ Cool stuff&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's sort of nice,
but also sort of rigid.
I didn't have anything to say in each four category each week,
so I either said something pointless anyway
or felt bad that the section was empty.&lt;/p&gt;
&lt;h3 id=&quot;too-much-effort&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#too-much-effort&quot;&gt;Too much effort&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I should have written only bullet points (and headings),
but I wrote full paragraphs, and &lt;em&gt;many&lt;/em&gt; of them.
I put way too much time and effort into something I originally wanted to be a chill little side quest.&lt;/p&gt;
&lt;p&gt;The reading experience could have been better too
had I written more shortly.
Sam Selikoff's Work journal (linked above) is nice to read because it's concise:
it has only headings and bullet points,
and most bullet points are short (even only one sentence).
Who wants to read too lengthy ramblings? Yeah, like this very text here.&lt;/p&gt;
&lt;p&gt;Also, the posts could have been regular blog posts with a &amp;quot;Weekly log&amp;quot; tag.
Why complicate things?&lt;/p&gt;
&lt;h2 id=&quot;lessons-learned&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#lessons-learned&quot;&gt;Lessons learned&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next time I'll think twice before committing to an arbitrary schedule.
Publishing something regularly is nice,
but not if it starts to feel like work.&lt;/p&gt;
&lt;p&gt;Next time I'll also try to keep things simple and flexible.
My weekly log entries could have been regular blog posts with only headings and bullet points.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/from-windows-to-mac/</id><title>Switching to Mac after 20+ years of using Windows</title><link href="https://mtsknn.fi/blog/from-windows-to-mac/" /><published>2023-01-31T12:00:00+03:00</published><updated>2023-01-31T12:00:00+03:00</updated><category term="Mac"></category><content type="html">&lt;p&gt;I have used Windows PCs since I was a kid.
A year ago (Jan 2022) I got my first MacBook.
While Mac isn't perfect,
it's so much better that I'm not going back to Windows.&lt;/p&gt;
&lt;h2 id=&quot;why-i-switched-to-mac&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-i-switched-to-mac&quot;&gt;Why I switched to Mac&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I had long had the impression that many developers use and like Macs,
so I was intrigued to try it myself.&lt;/li&gt;
&lt;li&gt;Macs are relatively expensive
(same amount of money gets you more horsepower if you buy a Windows PC,
though I'm not sure if M1/M2 Macs have changed the game),
and I'm a cheapo.&lt;/li&gt;
&lt;li&gt;A year ago (Jan 2022) I switched jobs
and could freely choose a work laptop (a great perk by the way),
so I took the opportunity and chose a MacBook.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;how-long-it-took-me-to-get-familiar-with-mac&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-long-it-took-me-to-get-familiar-with-mac&quot;&gt;How long it took me to get familiar with Mac&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Only about three days:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thu: fetched my MacBook from the office&lt;/li&gt;
&lt;li&gt;Fri–Sun: got to know the MacBook, configured things, installed apps&lt;/li&gt;
&lt;li&gt;Mon: started my new consulting gig&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first work days consisted mostly of introductions to the customer's systems etc.,
but even if the very first work day was full of coding,
I feel I wouldn't have been any more productive had I used a Windows PC
(because of the pros of Mac, listed below).&lt;/p&gt;
&lt;p&gt;It was a bit risky to switch from Windows to Mac with such a short time frame,
but it was worth it.&lt;/p&gt;
&lt;h2 id=&quot;things-i-like-in-mac&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#things-i-like-in-mac&quot;&gt;Things I like in Mac&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;unix&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#unix&quot;&gt;Unix&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Mac is a Unix operating system, so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terminal works great and is fast
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gitforwindows.org/&quot; class=&quot;link link-external&quot;&gt;Git Bash for Windows&lt;/a&gt; is slow in comparison&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/wsl/about&quot; class=&quot;link link-external&quot;&gt;WSL (Windows Subsystem for Linux)&lt;/a&gt;
felt fragile and had performance issues last time I used it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Unix tools work out of the box
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ohmyz.sh/&quot; class=&quot;link link-external&quot;&gt;Oh My Zsh&lt;/a&gt; gave me a nice Terminal experience very easily&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;fast&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fast&quot;&gt;Fast&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The hardware matters as well;
I switched from Lenovo ThinkPad X1 Carbon Gen 7
to MacBook Pro 16&amp;quot; M1 Pro (32 GB).&lt;/p&gt;
&lt;p&gt;My MacBook is not as fast as I thought –
I had read high praises from several sources,
so my expectations were very high –
but it's still fast.&lt;/p&gt;
&lt;p&gt;Every time I use my Windows laptop
I'm baffled how sluggish it is.
So compared to that,
yes, my MacBook is very fast.&lt;/p&gt;
&lt;h3 id=&quot;better-keyboard-shortcuts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#better-keyboard-shortcuts&quot;&gt;Better keyboard shortcuts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using the &lt;kbd&gt;Cmd&lt;/kbd&gt; key (next to the space bar) with the left thumb
is more ergonomic than reaching for the &lt;kbd&gt;Ctrl&lt;/kbd&gt; key with the left pinky.&lt;/p&gt;
&lt;h2 id=&quot;things-i-miss-from-windows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#things-i-miss-from-windows&quot;&gt;Things I miss from Windows&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;the-menu-keyboard-key&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-menu-keyboard-key&quot;&gt;The Menu keyboard key&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Menu_key&quot; class=&quot;link link-external&quot;&gt;Menu key&lt;/a&gt;
is essential for comfortable keyboard navigation across Windows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computing, the &lt;strong&gt;menu key&lt;/strong&gt; or &lt;strong&gt;application key&lt;/strong&gt; (&lt;kbd&gt;≣ Menu&lt;/kbd&gt;) is a key found on Microsoft Windows-oriented computer keyboards [...]. It is typically found on the right side of the keyboard between the right Windows logo key and the right control key [...].&lt;/p&gt;
&lt;p&gt;The key's primary function is to launch a context menu with the keyboard rather than with the usual right-mouse button. It can be used when the right-mouse button is not present on a mouse.&lt;/p&gt;
&lt;p&gt;[...] In many Windows applications, a similar functionality can be invoked with the &lt;kbd&gt;⇧ Shift&lt;/kbd&gt;+&lt;kbd&gt;F10&lt;/kbd&gt; keyboard shortcut [...].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I used the Menu key (or sometimes &lt;kbd&gt;Shift&lt;/kbd&gt;+&lt;kbd&gt;F10&lt;/kbd&gt;) all the time.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://apple.stackexchange.com/q/32715/111704&quot; class=&quot;link link-external&quot;&gt;Mac doesn't have a Menu key.&lt;/a&gt;
Such a shame.
An accessibility issue as well.&lt;/p&gt;
&lt;h3 id=&quot;alt-tabbing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#alt-tabbing&quot;&gt;Alt-tabbing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The default alt-tabbing experience on Mac is poor.
No window previews like on Windows,
and &lt;a href=&quot;https://apple.stackexchange.com/q/112350/111704&quot; class=&quot;link link-external&quot;&gt;the keyboard shortcut for alt-tabbing to a hidden or minimized window is crazily complex&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Switching between the windows of a single app with &lt;kbd&gt;Cmd&lt;/kbd&gt;+&lt;kbd&gt;`&lt;/kbd&gt;
is cool though.&lt;/p&gt;
&lt;p&gt;I use a free app called &lt;a href=&quot;https://alt-tab-macos.netlify.app/&quot; class=&quot;link link-external&quot;&gt;AltTab&lt;/a&gt;
which &amp;quot;brings the power of Windows's 'alt-tab' window switcher to macOS.&amp;quot;
Unfortunately it's a bit buggy
(because &lt;a href=&quot;https://alt-tab-macos.netlify.app/contributing&quot; class=&quot;link link-external&quot;&gt;&amp;quot;Mac development ecosystem is pretty terrible in general&amp;quot;&lt;/a&gt;),
but it's 90% great and much better than the default alt-tabbing experience on Mac.&lt;/p&gt;
&lt;h3 id=&quot;middle-clicking-on-the-trackpad&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#middle-clicking-on-the-trackpad&quot;&gt;Middle-clicking on the trackpad&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I'm used to middle-clicking by tapping the trackpad with three fingers.
That's not possible on MacBook's trackpad though.&lt;/p&gt;
&lt;p&gt;The free app called &lt;a href=&quot;https://github.com/artginzburg/MiddleClick-Ventura&quot; class=&quot;link link-external&quot;&gt;MiddleClick&lt;/a&gt;
fixes that,
but it's a bit buggy.&lt;/p&gt;
&lt;p&gt;There are paid alternatives,
but I'm not willing to pay several euros for a feature that should be part of core Mac.
(I already said I'm a cheapo.)&lt;/p&gt;
&lt;p&gt;It's baffling that I need a 3rd party app for this basic feature.&lt;/p&gt;
&lt;h3 id=&quot;gaming&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#gaming&quot;&gt;Gaming&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I rarely play video games,
but I miss Battlefield 4.
I'd also love to try Age of Empires IV.&lt;/p&gt;
&lt;p&gt;Mac runs some games, but of course not those two I'm interested in.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hanki.dev/just-do-it/&quot; class=&quot;link link-external&quot;&gt;My bro recently built a Windows gaming PC&lt;/a&gt;,
which made me want to build one too.&lt;/p&gt;
&lt;h2 id=&quot;things-that-are-bad-both-in-windows-and-mac&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#things-that-are-bad-both-in-windows-and-mac&quot;&gt;Things that are bad both in Windows and Mac&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;focus-stealing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#focus-stealing&quot;&gt;Focus stealing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I truly &lt;em&gt;hated&lt;/em&gt; focus stealing on Windows.
It's so annoying when you are doing something
and another app/window suddenly steals focus,
interrupting your typing/clicking/whatever.&lt;/p&gt;
&lt;p&gt;Focus stealing is a problem on Mac too,
albeit not as big a problem.
&lt;a href=&quot;https://krisp.ai/&quot; class=&quot;link link-external&quot;&gt;Krisp&lt;/a&gt; is maybe the worst offender I have encountered so far.&lt;/p&gt;
&lt;p&gt;I had &lt;a href=&quot;https://news.ycombinator.com/item?id=31752926&quot; class=&quot;link link-external&quot;&gt;reaperducer's Hacker News comment about focus stealing on Macs&lt;/a&gt;
saved on my bookmarks.
It's a good comment;
here's a snippet:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think allowing any pop-up to demand focus is a serious security flaw. I've sometimes found myself typing a password into a browser, or a word processor, because they've decided that they are the most important thing in my life at that moment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, focus stealing is not only an annoyance but a security risk as well.&lt;/p&gt;
&lt;h2 id=&quot;verdict&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#verdict&quot;&gt;Verdict&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like Mac because it's fast and a Unix system and generally just feels good.&lt;/p&gt;
&lt;p&gt;Mac required some tweaking to make me feel at home,
but what system doesn't require tweaking?
The Windows experience isn't optimal out of the box either.&lt;/p&gt;
&lt;p&gt;After a year of using Mac and touching Windows only a few times,
I don't see myself going back to Windows, except maybe for gaming.
Though it didn't take a full year for me to feel this way;
only a few days or weeks.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-retry-on-fail/</id><title>Automatically retrying a failing function in JS/TS</title><link href="https://mtsknn.fi/blog/js-retry-on-fail/" /><published>2022-12-14T12:00:00+03:00</published><updated>2023-03-20T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;A little helper function
to retry a function automatically a limited number of times (or until success)
and with a certain delay between retries.
Useful e.g. when working with a flaky API.&lt;/p&gt;
&lt;h2 id=&quot;starting-point&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#starting-point&quot;&gt;Starting point&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After a bit of googling,
I found &lt;a href=&quot;https://stackoverflow.com/a/42429685/1079869&quot; class=&quot;link link-external&quot;&gt;Jaromanda X's answer on Stack Overflow&lt;/a&gt;
to be a good starting point:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Using a couple of helper functions I've used a lot, this becomes very easy&lt;/p&gt;
&lt;p&gt;The &amp;quot;helpers&amp;quot;&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cont&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cont &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cont &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; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'failed'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;myMainFuntion&lt;/span&gt;&lt;span class=&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;var&lt;/span&gt; delay &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 punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; tries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tryAsync&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Works well,
but let's do better since the code wasn't immediately clear for me.&lt;/p&gt;
&lt;h2 id=&quot;refactoring-step-by-step&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#refactoring-step-by-step&quot;&gt;Refactoring step by step&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's do an unsolicited code review
and refactor the code along the way.
You can also &lt;a href=&quot;#final-result&quot; class=&quot;link link-anchor&quot;&gt;jump straight to the final result&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The general rule of code reviewing seems to apply here:
the shorter the code, the more it receives comments.&lt;/p&gt;
&lt;h3 id=&quot;step-1-prettier&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-1-prettier&quot;&gt;Step 1: Prettier&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The lines declaring the two helpers are very long: 80 and 161 characters.&lt;/p&gt;
&lt;p&gt;Too long lines are difficult to read.
Especially the &lt;code&gt;retry&lt;/code&gt; method in this case.&lt;/p&gt;
&lt;p&gt;Let's format the code with Prettier:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cont&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&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;err&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;
    cont &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cont &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; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'failed'&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the structure of the code is much easier to see.
Looks like &lt;code&gt;Promise.retry&lt;/code&gt; is a recursive function.&lt;/p&gt;
&lt;h3 id=&quot;step-2-no-monkey-patching&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-2-no-monkey-patching&quot;&gt;Step 2: no monkey patching&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/q/6223449/1079869&quot; class=&quot;link link-external&quot;&gt;Modifying global prototypes is generally not a good idea&lt;/a&gt;,
so instead of adding the methods to the global &lt;code&gt;Promise&lt;/code&gt; object,
let's convert the methods to standalone functions.&lt;/p&gt;
&lt;p&gt;Diff:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;   &lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&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;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cont&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cont&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&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;err&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 prefix unchanged&quot;&gt; &lt;/span&gt;    cont &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cont &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; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;         &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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 function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cont &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; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'failed'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result (formatted with Prettier; &lt;code&gt;wait&lt;/code&gt; function moved to the end):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cont&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&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;err&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;
    cont &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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 function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cont &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; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'failed'&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-whats-cont&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-3-whats-cont&quot;&gt;Step 3: what's &amp;quot;cont&amp;quot;?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What is the &lt;code&gt;cont&lt;/code&gt; parameter for –
what does &amp;quot;cont&amp;quot; mean?&lt;/p&gt;
&lt;p&gt;I guess it means something like &amp;quot;continue/retry if this is greater than 0.&amp;quot;
In other words,
it's the number of remaining retries.&lt;/p&gt;
&lt;p&gt;Let's rename &lt;code&gt;cont&lt;/code&gt; to &lt;code&gt;retries&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cont&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-4-order-of-parameters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-4-order-of-parameters&quot;&gt;Step 4: order of parameters&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Is the order of the parameters ideal?&lt;/p&gt;
&lt;p&gt;Now the function reads like
&amp;quot;&lt;code&gt;retry&lt;/code&gt; with x &lt;code&gt;retries&lt;/code&gt; the given &lt;code&gt;fn&lt;/code&gt; with a &lt;code&gt;delay&lt;/code&gt; of y milliseconds.&amp;quot;
Sounds clumsy.&lt;/p&gt;
&lt;p&gt;If the first two parameters are swapped:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...the function reads like
&amp;quot;&lt;code&gt;retry&lt;/code&gt; the given &lt;code&gt;fn&lt;/code&gt; with x &lt;code&gt;retries&lt;/code&gt; and a &lt;code&gt;delay&lt;/code&gt; of y milliseconds.&amp;quot;&lt;/p&gt;
&lt;p&gt;I think that's better –
the &lt;code&gt;fn&lt;/code&gt; parameter is the &amp;quot;main&amp;quot; parameter,
and the other two parameters are configurable options,
so it makes sense to pass the function as the first parameter.&lt;/p&gt;
&lt;h3 id=&quot;step-5-options-parameter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-5-options-parameter&quot;&gt;Step 5: options parameter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let's continue with the parameters.&lt;/p&gt;
&lt;p&gt;When calling &lt;code&gt;retry&lt;/code&gt;, the purpose of the two option parameters is not clear:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myFn&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 number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// What 2? What 200?&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Condensing the options into a single object
makes the call site clearer:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&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 punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// Usage:&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myFn&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 number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// huh?&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myFn&lt;span class=&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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&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;// oh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-6-delay-parameter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-6-delay-parameter&quot;&gt;Step 6: delay parameter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Is the &lt;code&gt;delay&lt;/code&gt; option clear?
What does it delay – only the retries or also the initial function call?&lt;/p&gt;
&lt;p&gt;Let's rename &lt;code&gt;delay&lt;/code&gt; to &lt;code&gt;retryInterval&lt;/code&gt;
to make it clear that it's only about the retries,
not the initial function call.
Actually, let's use &lt;code&gt;retryIntervalMs&lt;/code&gt; to also clarify that the unit is milliseconds:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retryIntervalMs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// Usage:&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myFn&lt;span class=&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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &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 class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myFn&lt;span class=&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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;retryIntervalMs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another benefit: now the two options are sorted alphabetically. :D&lt;/p&gt;
&lt;p&gt;Similarly, let's rename the &lt;code&gt;wait&lt;/code&gt; function's &lt;code&gt;time&lt;/code&gt; parameter to &lt;code&gt;ms&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms   &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-7-function-name&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-7-function-name&quot;&gt;Step 7: function name&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;More bike-shedding:
does the name &lt;code&gt;retry&lt;/code&gt; tell clearly what the function does?&lt;/p&gt;
&lt;p&gt;Yes, the function retries another function –
but only after the initial try, which is a &lt;em&gt;try&lt;/em&gt;, not a &lt;em&gt;re-try&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Something like &lt;code&gt;tryAndRetry&lt;/code&gt; or &lt;code&gt;retryOnFail&lt;/code&gt; or &lt;code&gt;tryMultipleTimes&lt;/code&gt; could be more descriptive.
Though these are quite wordy and still not great.&lt;/p&gt;
&lt;p&gt;Apparently this whole thing is called &amp;quot;retry pattern&amp;quot; or &amp;quot;retry design pattern&amp;quot;
(more about this in the &lt;a href=&quot;#further-resources&quot; class=&quot;link link-anchor&quot;&gt;&lt;em&gt;Further resources&lt;/em&gt; section&lt;/a&gt;),
so let's actually keep the &lt;code&gt;retry&lt;/code&gt; name.&lt;/p&gt;
&lt;p&gt;But thinking about this was useful:
we can deduce that because the first &lt;code&gt;fn&lt;/code&gt; call is a try and not a retry,
the maximum number of &lt;code&gt;fn&lt;/code&gt; calls should be &lt;code&gt;1 + retries&lt;/code&gt;.
And indeed it is.
(If the maximum number was something else,
the option name &lt;code&gt;retries&lt;/code&gt; could be confusing.)&lt;/p&gt;
&lt;p&gt;Here's what we have so far:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retryIntervalMs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&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;err&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;
    retries &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retryIntervalMs&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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 function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; retries &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; retryIntervalMs &lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'failed'&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-8-better-error&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-8-better-error&quot;&gt;Step 8: better error&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If the last retry also fails,
&lt;code&gt;retry&lt;/code&gt; throws the string &lt;code&gt;'failed'&lt;/code&gt;.
Re-throwing the error thrown by &lt;code&gt;fn&lt;/code&gt; is likely more useful.&lt;/p&gt;
&lt;p&gt;While at it, let's also rename &lt;code&gt;err&lt;/code&gt; to &lt;code&gt;error&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;retry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retryIntervalMs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&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;err&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&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;error&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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;    retries &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retryIntervalMs&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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 prefix unchanged&quot;&gt; &lt;/span&gt;          &lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; retries &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; retryIntervalMs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'failed'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-9-typescript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-9-typescript&quot;&gt;Step 9: TypeScript&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; retry &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 constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;fn&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retryIntervalMs &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; retries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; retryIntervalMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&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 builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
    retries &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retryIntervalMs&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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 function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; retries &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; retryIntervalMs &lt;span class=&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 builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;wait&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;ms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&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;&lt;span class=&quot;token builtin&quot;&gt;Promise&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generic parameter &lt;code&gt;T&lt;/code&gt; is used more than once in the function signature,
so this is a good use of generics;
see &lt;a href=&quot;https://effectivetypescript.com/2020/08/12/generics-golden-rule/&quot; class=&quot;link link-external&quot;&gt;The Golden Rule of Generics&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-10-the-need-for-async-await&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-10-the-need-for-async-await&quot;&gt;Step 10: the need for &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So far so good,
but there's a caveat:&lt;/p&gt;
&lt;p&gt;The provided function must be async (marked with &lt;code&gt;async&lt;/code&gt; or returns a Promise),
or the function won't be retried.&lt;/p&gt;
&lt;h4&gt;Async functions&lt;/h4&gt;
&lt;p&gt;Async functions work well:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; options &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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;retryIntervalMs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; returns 42&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; returns 42&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&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 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 string&quot;&gt;'hi'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'fail'&lt;/span&gt;&lt;span class=&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; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (initial try)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (1st retry)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (2nd retry)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; throws [Error: fail]&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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 string&quot;&gt;'hi'&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&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;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'fail'&lt;/span&gt;&lt;span class=&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; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (initial try)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (1st retry)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (2nd retry)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; throws [Error: fail]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Non-async functions&lt;/h4&gt;
&lt;p&gt;Non-async functions don't work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Non-async functions are not retried:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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 string&quot;&gt;'hi'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'fail'&lt;/span&gt;&lt;span class=&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; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (initial try)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; throws [Error: fail]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If a non-async function succeeds, a TypeError will still be thrown:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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 string&quot;&gt;'hi'&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 number&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (initial try)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; throws [TypeError: fn(...).catch is not a function]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;&lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; vs Promises&lt;/h4&gt;
&lt;p&gt;TypeScript won't allow passing a non-async function to &lt;code&gt;retry&lt;/code&gt;,
but I don't like that &lt;code&gt;retry&lt;/code&gt; breaks at runtime if it's given a non-async function.&lt;/p&gt;
&lt;p&gt;Let's eliminate the caveat by refactoring to &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An alternative would be to make &lt;code&gt;retry&lt;/code&gt; always return a Promise.
The code wouldn't be as clear in my opinion,
and there would be the extra caveat of having to avoid the pitfalls of the
&lt;a href=&quot;https://stackoverflow.com/q/23803743/1079869&quot; class=&quot;link link-external&quot;&gt;explicit Promise constructor anti-pattern&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-11-async-await&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-11-async-await&quot;&gt;Step 11: &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Diff:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-ts&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; retry &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 constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token function-variable function&quot;&gt;fn&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-ts&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; retry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token function-variable function&quot;&gt;fn&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-ts&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retryIntervalMs &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; retries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; retryIntervalMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-ts&quot;&gt;&lt;span class=&quot;token prefix deleted&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 builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&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 prefix deleted&quot;&gt;-&lt;/span&gt;    retries &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retryIntervalMs&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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 prefix deleted&quot;&gt;-&lt;/span&gt;          &lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; retries &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; retryIntervalMs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-ts&quot;&gt;&lt;span class=&quot;token prefix inserted&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 builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&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 prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retries &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retryIntervalMs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; retries &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; retryIntervalMs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token deleted-sign deleted language-ts&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;wait&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;ms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&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;&lt;span class=&quot;token builtin&quot;&gt;Promise&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms&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 class=&quot;token inserted-sign inserted language-ts&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;sleep&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;ms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&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;&lt;span class=&quot;token builtin&quot;&gt;Promise&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Heh, only one non-empty line remained unchanged.)&lt;/p&gt;
&lt;p&gt;Details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I renamed &lt;code&gt;wait&lt;/code&gt; to &lt;code&gt;sleep&lt;/code&gt; because &lt;code&gt;await wait()&lt;/code&gt; would look awkward.&lt;/li&gt;
&lt;li&gt;This version works also with non-async functions
because &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#conversion_to_promise&quot; class=&quot;link link-external&quot;&gt;the &lt;code&gt;await&lt;/code&gt; operator converts non-Promise values to resolved Promises&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;return&lt;/code&gt; vs &lt;code&gt;return await&lt;/code&gt;:
&lt;a href=&quot;https://jakearchibald.com/2017/await-vs-return-vs-return-await/&quot; class=&quot;link link-external&quot;&gt;&amp;quot;Outside of try/catch blocks, &lt;code&gt;return await&lt;/code&gt; is redundant.&amp;quot;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;final-result&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#final-result&quot;&gt;Final result&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/**
 * Runs the function `fn`
 * and retries automatically if it fails.
 *
 * Tries max `1 + retries` times
 * with `retryIntervalMs` milliseconds between retries.
 *
 * From https://mtsknn.fi/blog/js-retry-on-fail/
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; retry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;fn&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retryIntervalMs &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; retries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; retryIntervalMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&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 builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&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;try&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 keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retries &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error
    &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 function&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retryIntervalMs&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 function&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; retries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; retries &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; retryIntervalMs &lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;sleep&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;ms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&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;&lt;span class=&quot;token builtin&quot;&gt;Promise&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looks quite good to me!&lt;/p&gt;
&lt;h3 id=&quot;usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#usage&quot;&gt;Usage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Happy cases:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; options &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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;retryIntervalMs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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 number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; 42&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; 42&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; 42&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Error cases:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; options &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;retries&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;retryIntervalMs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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 string&quot;&gt;'hi'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'fail'&lt;/span&gt;&lt;span class=&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; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (initial try)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (1st retry)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; logs 'hi' (2nd retry)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; throws [Error: fail]&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&lt;/span&gt;&lt;span class=&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 string&quot;&gt;'hi'&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; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&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;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'fail'&lt;/span&gt;&lt;span class=&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; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; same as above&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;retry&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 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 string&quot;&gt;'hi'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'fail'&lt;/span&gt;&lt;span class=&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; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; same as above&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This blog post was almost ready when I found
&lt;a href=&quot;https://stackoverflow.com/q/38213668/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Promise Retry Design Patterns&lt;/em&gt; on Stack Overflow&lt;/a&gt;.
These three answers are interesting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/55270741/1079869&quot; class=&quot;link link-external&quot;&gt;Red Mercury's answer&lt;/a&gt;
uses the &lt;a href=&quot;https://en.wikipedia.org/wiki/Exponential_backoff&quot; class=&quot;link link-external&quot;&gt;exponential backoff algorithm&lt;/a&gt;.
This led me to find
&lt;a href=&quot;https://github.com/sindresorhus/p-retry&quot; class=&quot;link link-external&quot;&gt;p-retry, a library that also uses the exponential backoff algorithm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/62442746/1079869&quot; class=&quot;link link-external&quot;&gt;Bryan McGrane's answer&lt;/a&gt;
is almost identical to my final result.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/63750676/1079869&quot; class=&quot;link link-external&quot;&gt;Nacho Coloma's answer&lt;/a&gt;
is also similar, but uses a &lt;code&gt;for&lt;/code&gt; loop instead of recursion.
Though this version retries only if the given function returns &lt;code&gt;undefined&lt;/code&gt;,
not if it throws.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/swr-show-stale-data-on-revalidation-error/</id><title>SWR (v1): show previous/stale data on revalidation errors</title><link href="https://mtsknn.fi/blog/swr-show-stale-data-on-revalidation-error/" /><published>2022-11-08T12:00:00+03:00</published><updated>2023-05-12T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;If I'm already displaying data that I have successfully fetched with SWR,
and then another fetch call fails (when revalidating the data),
I don't want to replace the data view with an error view.
Here's how to avoid that.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Basic usage of &lt;a href=&quot;https://swr.vercel.app/&quot; class=&quot;link link-external&quot;&gt;SWR&lt;/a&gt;
(v1; I haven't upgraded to v2 yet):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;useItems&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;=&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; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useSWR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/api/items/'&lt;/span&gt;&lt;span class=&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;url&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 function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&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; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;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 literal-property property&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&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;isLoadingItems&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;data &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;failedToLoadItems&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;error&lt;span class=&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 function&quot;&gt;Items&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; isLoadingItems&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; failedToLoadItems &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useItems&lt;/span&gt;&lt;span class=&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; isLoadingItems &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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Loading...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; failedToLoadItems &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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;No items&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;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 punctuation&quot;&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;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&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 plain-text&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My problem occurs with these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SWR starts to fetch initial data, app shows loading state.&lt;/li&gt;
&lt;li&gt;SWR has fetched data, app shows data.&lt;/li&gt;
&lt;li&gt;SWR starts to fetch data again (revalidation), app still shows data.&lt;/li&gt;
&lt;li&gt;SWR fails to fetch data (e.g. the API endpoint fails), app shows error state.
&lt;ul&gt;
&lt;li&gt;Here I don't want the app to show error state;
I want it to keep showing the previous (stale) data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I spent some time looking for a solution
until I realized that it's very simple –
let the failed state be &lt;code&gt;false&lt;/code&gt;
only if there's no data (i.e. if &lt;code&gt;data&lt;/code&gt; is not falsy):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;useItems&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;=&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; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useSWR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/api/items/'&lt;/span&gt;&lt;span class=&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;url&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 function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&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; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;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 literal-property property&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&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;isLoadingItems&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;data &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;failedToLoadItems&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;data &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&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 function&quot;&gt;Items&lt;/span&gt;&lt;span class=&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;// Same as before&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;truth-tables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#truth-tables&quot;&gt;Truth tables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I built these truth tables to be sure that the change works as expected.&lt;/p&gt;
&lt;h3 id=&quot;before-the-change&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#before-the-change&quot;&gt;Before the change&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;data&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;error&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;isLoading&lt;/code&gt;&lt;br&gt;(&lt;code&gt;!data &amp;amp;&amp;amp; !error&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;failedToLoad&lt;/code&gt;&lt;br&gt;(&lt;code&gt;!!error&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;state description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;initial state or revalidation succeeded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;initial fetch succeeded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;initial fetch failed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;revalidation failed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;after-the-change&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#after-the-change&quot;&gt;After the change&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Only the 4th column and the last row are different:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;data&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;error&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;isLoading&lt;/code&gt;&lt;br&gt;(&lt;code&gt;!data &amp;amp;&amp;amp; !error&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;failedToLoad&lt;/code&gt;&lt;br&gt;(&lt;code&gt;!data &amp;amp;&amp;amp; !!error&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;state description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;initial state or revalidation succeeded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;initial fetch succeeded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;falsy&lt;/td&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;initial fetch failed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;truthy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt; (&lt;code&gt;true&lt;/code&gt; in the other table)&lt;/td&gt;
&lt;td&gt;revalidation failed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;LGTM!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/burnout/</id><title>Wild ideas to avoid burnout</title><link href="https://mtsknn.fi/blog/burnout/" /><published>2022-11-07T12:00:00+03:00</published><updated>2022-11-07T12:00:00+03:00</updated><category term="Work–life balance"></category><content type="html">&lt;p&gt;Care less,
take a sabbatical,
get a second job,
get monster ear protection,
hide behind your manager.&lt;/p&gt;
&lt;p&gt;Someone recently &lt;a href=&quot;https://news.ycombinator.com/item?id=33260525&quot; class=&quot;link link-external&quot;&gt;asked on Hacker News if anyone has managed to find enjoyment in their work after burnout&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Excerpts from comments that I liked
(not all are that wild, but anyway):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=33261345&quot; class=&quot;link link-external&quot;&gt;&lt;strong&gt;Care less&lt;/strong&gt;&lt;/a&gt;
(comment by highwaylights)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This advice is going to be hated by a lot of people but... care less.&lt;/p&gt;
&lt;p&gt;You're in an industry that values your skills and seems to always have demand.
Whether or not that's true in the future,
it certainly is &lt;em&gt;today&lt;/em&gt;,
so the best thing you can do is put yourself first and worry less about work as a whole.
Especially if it's not your own company.&lt;/p&gt;
&lt;p&gt;Spend more time on you, on activities with friends and family, on hobbies.
If you don't have particularly healthy hobbies, maybe start some.
Getting &lt;em&gt;away&lt;/em&gt; from your work more and more will make it all the more bearable.&lt;/p&gt;
&lt;p&gt;These days work is close to the bottom of my list of concerns,
which sounds really bad – BUT –
I find I'm more productive than I've been in years
&lt;em&gt;because&lt;/em&gt; I'm not worrying if something takes longer than expected or is bigger than I realised.
I can just enjoy the problem solving and shipping without the stress.&lt;/p&gt;
&lt;p&gt;If you're burned out this badly I'd suggest it's your soul's way of telling yourself
&amp;quot;hey this isn't working for me&amp;quot;.
As someone who has been to some pretty messed up depths with the anxiety monster,
I'd heed that voice.
Life isn't long enough to stay stuck in a rut like this for any amount of time at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Caring less doesn't mean doing sloppy work,
nor does it mean not caring about the quality of your work.&lt;/p&gt;
&lt;p&gt;It means not taking work things too seriously (no one's life is at stake),
not having too strong opinions on everything (so you can avoid tiring debates; pick your battles),
not involving in office politics.&lt;/p&gt;
&lt;p&gt;It means focusing on the fun things,
like technical challenges,
clean code practices (yea I like them),
documenting your learnings (and later blogging about them).&lt;/p&gt;
&lt;p&gt;Another way of saying &amp;quot;care less&amp;quot; (comment by _fat_santa):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think a better way of putting it is: &amp;quot;don't get too emotionally invested&amp;quot;.
Writing code I often times get emotionally invested in its success,
but with a job you have to create that clear line of &amp;quot;I care, but I'm not emotionally invested&amp;quot;.
I really want to fix that bug in the system but if 5PM hits,
I don't have the emotional investment to keep going into the night like with a side project,
I can get to it in the morning.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Stopping early and continuing the next day is important,
but sometimes I fail to do that.
Like &amp;quot;one more turn&amp;quot; when playing Civilization,
&amp;quot;ten more minutes&amp;quot; often gets out of hand (comment by SoftTalker):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I used to be the sort of person who would stay at work
until I got to what felt like a &amp;quot;good&amp;quot; stopping point in what I was doing.
If something wasn't working,
and seemed like another 30 minutes might fix it,
I would often do it.
Of course 30 minutes often turned into 3 hours.&lt;/p&gt;
&lt;p&gt;Now I'm much more likely to just go home at the end of the day.
I don't really care what fires are burning,
they will be there tomorrow and nobody will die.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Saying &amp;quot;care less&amp;quot; is like saying &amp;quot;stress less,&amp;quot;
but the latter is difficult to implement on its own;
you need other tools for that (e.g. caring less).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=33261218&quot; class=&quot;link link-external&quot;&gt;&lt;strong&gt;Take a sabbatical&lt;/strong&gt;&lt;/a&gt;
(comments by samatman)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can you afford a sabbatical?&lt;/p&gt;
&lt;p&gt;The term has roots in &amp;quot;seven&amp;quot;, just like Sabbath,
so with 14 years in the industry,
you've skipped one.&lt;/p&gt;
&lt;p&gt;I think a solid half-year off every seven to ten years
is an excellent practice for intellectually demanding labor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ooh, I suddenly feel like I'd like to take a sabbatical!
Even 6 months would be nice.&lt;/p&gt;
&lt;p&gt;A sabbatical is not a vacation;
it's time to work on your passion projects:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What makes it a sabbatical is that it's a change of pace which furthers your career.
I'd love to take a sabbatical and just work on building stuff, personally:
from soldering, to designing boards, probing them, writing firmware,
I'm a rank amateur, and I'd love to level up for a while,
while free of the burden of justifying my salary in the process.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;What it isn't, is a vacation, or a convalescence&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.
It sounds like you haven't hit &amp;quot;can't work&amp;quot;, just &amp;quot;sucks to work&amp;quot;, which is a blessing.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;I've known people who pushed &amp;quot;sucks to work&amp;quot; until it became &amp;quot;can't work&amp;quot;,
and they don't all make it back to the profession,
a bit less than half in fact.
Whatever you do,
I urge you to take burnout seriously,
because at the limit it's a serious medical condition which can cripple or kill you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When looking for a job after the sabbatical,
saying that you took a sabbatical sounds better
than saying that you took a year off:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A sabbatical is not a gap in one's resume, it's a sabbatical.
What's done with that time is open-ended,
but one of the things it does is provide a useful line item.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;A sabbatical is good if:
you can write an open-source library in your niches which solves a problem,
if you expand the breadth of your expertise,
if what you're doing has a significant philanthropic angle.
All of these can set someone up for a higher tier of job,
something with better prospects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even if you wouldn't achieve anything tangible during your sabbatical,
it should still bring great benefits:
less stress, fresh mind, more energy.&lt;/p&gt;
&lt;p&gt;If you are already burned out,
taking a year off might be better for your health.
If you are not,
a sabbatical could be a good tool to avoid that.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=33261325&quot; class=&quot;link link-external&quot;&gt;&lt;strong&gt;Get a second job&lt;/strong&gt;&lt;/a&gt;
(comment by aspyct)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For me, switching to 4 days a week was a huge improvement in my quality of life.
Now I've switched to 3,
and have a completely different second job 2 days a week.
And two days of rest.&lt;/p&gt;
&lt;p&gt;I love both, for different reasons,
but could never go back to a full week of IT,
or switch to a full week of my new job.
They balance fine,
but I don't think they can exist on their own.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Interesting idea!&lt;/p&gt;
&lt;p&gt;Having only one job and working only 3 or 4 days a week would be more optimal,
but not always financially feasible.
Getting a completely different second job would bring in more money
and also variation to days.&lt;/p&gt;
&lt;p&gt;Another good point:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think working 5 days a week, 8h a day on the same topic is insane.
I can't think of anything I would want to do for so many hours a day, almost every day.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's crazy how much people usually work (including me, ouch).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=33260975&quot; class=&quot;link link-external&quot;&gt;&lt;strong&gt;Get monster ear protection&lt;/strong&gt;&lt;/a&gt;
(comment by larve)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Get monster ear protection.
This has to be one of the revelations:
noise stresses me out &lt;em&gt;sooo&lt;/em&gt; much,
and I have been repressing it for so long.
I now have -35 dB + noise-cancelling earplugs
and can basically live in complete silence, in the noisiest environment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Noise stresses me out too, very much so,
and I too have been ignoring that.&lt;/p&gt;
&lt;p&gt;I walk on my treadmill for several hours every work day&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;,
and it's not a particularly silent device,
so I'm being exposed to a lot of noise.
That's gotta do something to my mind,
and not in a good way.&lt;/p&gt;
&lt;p&gt;I already own &lt;a href=&quot;https://www.sony.com/ug/electronics/headband-headphones/wh-1000xm3&quot; class=&quot;link link-external&quot;&gt;Sony WH-1000XM3 wireless noise-cancelling headphones&lt;/a&gt;,
and looks like &lt;a href=&quot;https://www.rtings.com/headphones/tools/table/94793&quot; class=&quot;link link-external&quot;&gt;RTINGS.com has rated them as having the best level of noise isolation&lt;/a&gt;
among 697 headphones that they have tested (as of Nov 7, 2022).
Nice!
So I just need to learn to use my headphones more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=33260963&quot; class=&quot;link link-external&quot;&gt;&lt;strong&gt;Hide behind your manager&lt;/strong&gt;&lt;/a&gt;
(comment by jnsaff2)&lt;sup&gt;&lt;a aria-label=&quot;footnote 3&quot; class=&quot;link&quot; href=&quot;#fn-3&quot; id=&quot;fnref-3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Whenever anyone asked me to stay late
I referred them to my manager for them to approve paid overtime.
Most of the time the discussion stopped there,
but there were a few times when they decided to pay.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There'll always be people who'll try to shamelessly take advantage of you.&lt;/p&gt;
&lt;p&gt;If setting boundaries on your own feels difficult,
one strategy is to delegate unpleasant discussions to another person,
like your manager.&lt;/p&gt;
&lt;p&gt;That's not cowardice;
that's saving your mental energy
by avoiding discussions that shouldn't happen in the first place
(no one should ask or except anyone to do unpaid overtime).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One more link:
&lt;a href=&quot;https://www.youtube.com/watch?v=HU0pZarehLY&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Do Nothing&lt;/em&gt; on YouTube (0:49) summarizes the &amp;quot;care less&amp;quot; category well&lt;/a&gt;.&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.dictionary.com/browse/convalescence&quot; class=&quot;link link-external&quot;&gt;Dictionary.com defines &lt;em&gt;convalescence&lt;/em&gt;&lt;/a&gt;
as &amp;quot;the gradual recovery of health and strength after illness.&amp;quot; &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;Walking is &lt;em&gt;sooo&lt;/em&gt; much better than sitting or standing still.
Blog post coming some day. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;&lt;p&gt;To be clear,
the comment doesn't directly say to &amp;quot;hide behind your manager.&amp;quot; &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/react-fallback-ref/</id><title>Four ways to use a fallback ref with `React.forwardRef`</title><link href="https://mtsknn.fi/blog/react-fallback-ref/" /><published>2022-10-19T12:00:00+03:00</published><updated>2022-10-19T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;A component wrapped in &lt;code&gt;React.forwardRef&lt;/code&gt;
normally expects to receive a ref from its parent component.
What if you want the component to have a ref
even if it doesn't receive one from its parent?&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactforwardref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;React.forwardRef&lt;/code&gt;&lt;/a&gt; allows passing a ref to a child component:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Parent&lt;/span&gt;&lt;span class=&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;return&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;&lt;span class=&quot;token class-name&quot;&gt;Child&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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 function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;forwardedRef&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;current&lt;span class=&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;forwardedRef&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;forwardedRef&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;When rendering &lt;code&gt;&amp;lt;Parent /&amp;gt;&lt;/code&gt;,
both &lt;code&gt;useEffect&lt;/code&gt;s log the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element from the &lt;code&gt;Child&lt;/code&gt; component:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;&lt;span class=&quot;token class-name&quot;&gt;Parent&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 comment&quot;&gt;// Logs `&amp;lt;div&gt;` twice&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But when rendering &lt;code&gt;&amp;lt;Child /&amp;gt;&lt;/code&gt; on its own,
the &lt;code&gt;Child&lt;/code&gt;'s &lt;code&gt;useEffect&lt;/code&gt; logs &lt;code&gt;undefined&lt;/code&gt;
because no ref is passed/forwarded:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;&lt;span class=&quot;token class-name&quot;&gt;Child&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 comment&quot;&gt;// Logs `undefined` once 😿&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More specifically:
&lt;code&gt;forwardedRef&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;,
so &lt;code&gt;forwardedRef?.current&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What if you want &lt;code&gt;Child&lt;/code&gt; to have a ref to its &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element
even when no ref is forwarded to &lt;code&gt;Child&lt;/code&gt;?
You can create a new ref in &lt;code&gt;Child&lt;/code&gt;,
but you can't attach both refs to the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// 🛑 JSX elements cannot have multiple attributes with the same name&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;forwardedRef&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;
      ...
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;desired-outcome&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#desired-outcome&quot;&gt;Desired outcome&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When rendering &lt;code&gt;&amp;lt;Parent /&amp;gt;&lt;/code&gt;,
both &lt;code&gt;useEffect&lt;/code&gt;s should still log the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element from the &lt;code&gt;Child&lt;/code&gt; component:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;&lt;span class=&quot;token class-name&quot;&gt;Parent&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 comment&quot;&gt;// Logs `&amp;lt;div&gt;` twice&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When rendering &lt;code&gt;&amp;lt;Child&amp;gt;&lt;/code&gt; on its own,
its &lt;code&gt;useEffect&lt;/code&gt; should log the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;&lt;span class=&quot;token class-name&quot;&gt;Child&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 comment&quot;&gt;// Logs `&amp;lt;div&gt;` once&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;four-solutions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#four-solutions&quot;&gt;Four solutions&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;useref-oror&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#useref-oror&quot;&gt;&lt;code&gt;useRef&lt;/code&gt; + &lt;code&gt;||&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a fallback ref with &lt;code&gt;useRef&lt;/code&gt;
and use it if &lt;code&gt;forwardedRef&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; fallbackRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; forwardedRef &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; fallbackRef

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or as a custom hook:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useFallbackRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&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 function&quot;&gt;useFallbackRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;forwardedRef&lt;/span&gt;&lt;span class=&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; fallbackRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; forwardedRef &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; fallbackRef
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Very simple and clear.
Maybe the simplest solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The fallback ref is created even when it's not needed,
but it's probably not a big deal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found this solution via
&lt;a href=&quot;https://github.com/brunoscopelliti/use-forward-ref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;brunoscopelliti/use-forward-ref&lt;/code&gt; on GitHub&lt;/a&gt;,
which was the only npm package found via
&lt;a href=&quot;https://www.npmjs.com/search?q=react%20fallback%20ref&quot; class=&quot;link link-external&quot;&gt;searching &amp;quot;react fallback ref&amp;quot; on npmjs.com&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;lazy-usestate-conditional-createref&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#lazy-usestate-conditional-createref&quot;&gt;Lazy &lt;code&gt;useState&lt;/code&gt; + conditional &lt;code&gt;createRef&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a fallback ref with &lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactcreateref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;React.createRef&lt;/code&gt;&lt;/a&gt;
if &lt;code&gt;forwardedRef&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To avoid creating a new ref every time the &lt;code&gt;Child&lt;/code&gt; component is re-rendered,
wrap the conditional ref creation in &lt;code&gt;useState&lt;/code&gt;
and use &lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#lazy-initial-state&quot; class=&quot;link link-external&quot;&gt;lazy initial state&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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;ref&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&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; forwardedRef &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRef&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or as a custom hook:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useFallbackRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&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 function&quot;&gt;useFallbackRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;forwardedRef&lt;/span&gt;&lt;span class=&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 function&quot;&gt;useState&lt;/span&gt;&lt;span class=&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; forwardedRef &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRef&lt;/span&gt;&lt;span class=&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 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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simple and reads like English:
use &lt;code&gt;forwardedRef&lt;/code&gt; if it exists (i.e. if it's not &lt;code&gt;null&lt;/code&gt;),
otherwise create a new ref.&lt;/li&gt;
&lt;li&gt;The fallback ref is created only when necessary.
(Probably doesn't matter though.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It's mildly confusing to mix hooks and the non-hook &lt;code&gt;createRef&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Simple because uses only the &lt;code&gt;useState&lt;/code&gt; hook,
though you do need to know about and understand &lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#lazy-initial-state&quot; class=&quot;link link-external&quot;&gt;lazy initial state&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I came up with this solution myself. 🤙&lt;/p&gt;
&lt;h3 id=&quot;useimperativehandle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#useimperativehandle&quot;&gt;&lt;code&gt;useImperativeHandle&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#useimperativehandle&quot; class=&quot;link link-external&quot;&gt;React's &lt;code&gt;useImperativeHandle&lt;/code&gt; hook&lt;/a&gt;
allows customizing the value of a forwarded ref.&lt;/p&gt;
&lt;p&gt;The docs for the hook are very terse
(emphasis added and example code slightly modified):&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useImperativeHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; createHandle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;deps&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;useImperativeHandle&lt;/code&gt; customizes the instance value
that is exposed to parent components when using &lt;code&gt;ref&lt;/code&gt;.&lt;/strong&gt;
As always, imperative code using refs should be avoided in most cases.
&lt;strong&gt;&lt;code&gt;useImperativeHandle&lt;/code&gt; should be used with &lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactforwardref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;forwardRef&lt;/code&gt;&lt;/a&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; FancyInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&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;useImperativeHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;focus&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;=&gt;&lt;/span&gt; ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&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;return&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example,
a parent component that renders &lt;code&gt;&amp;lt;FancyInput ref={inputRef} /&amp;gt;&lt;/code&gt;
would be able to call &lt;code&gt;inputRef.current.focus()&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the quoted example,
&lt;code&gt;inputRef.current&lt;/code&gt; has &lt;em&gt;only&lt;/em&gt; the &lt;code&gt;focus&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;To expose all methods and properties of the DOM element to the parent ref,
expose &lt;code&gt;ref.current&lt;/code&gt; as-is:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useImperativeHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef&lt;span class=&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; ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a ref is forwarded,
&lt;code&gt;forwardedRef.current&lt;/code&gt; and &lt;code&gt;ref.current&lt;/code&gt; will point to the same DOM element.&lt;/li&gt;
&lt;li&gt;If a ref is not forwarded,
&lt;code&gt;forwardedRef&lt;/code&gt; will still be &lt;code&gt;null&lt;/code&gt;,
but &lt;code&gt;ref&lt;/code&gt; will act as a fallback ref.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Put together:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useImperativeHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef&lt;span class=&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; ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;// `ref` is not needed here&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Notice we are using `ref` here, not `forwardedRef`&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or as a custom hook:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useFallbackRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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;// `ref` is needed again here&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&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 function&quot;&gt;useFallbackRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;forwardedRef&lt;/span&gt;&lt;span class=&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useImperativeHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef&lt;span class=&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; ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ref
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;useImperativeHandle&lt;/code&gt; hook is designed for
customizing the value of the forwarded ref,
so using it like this feels correct.&lt;/li&gt;
&lt;li&gt;ESLint knows that the &lt;code&gt;ref&lt;/code&gt; variable is stable,
so it doesn't need to be included in the &lt;code&gt;useEffect&lt;/code&gt;'s dependency array,
making the code clearer.
(Though ESLint won't know that &lt;code&gt;ref&lt;/code&gt; is stable when using the custom hook.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;useImperativeHandle&lt;/code&gt; hook is exotic and probably only rarely used.
If you have never heard of it before,
you can't know how it works at a first glance.
(Compared to &lt;code&gt;useState&lt;/code&gt;,
which is maybe the most basic hook
and should be familiar to any React dev.)&lt;/li&gt;
&lt;li&gt;The fallback ref is created even when it's not needed,
but it's probably not a big deal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found this solution via
&lt;a href=&quot;https://jaketrent.com/post/fallback-ref-react&quot; class=&quot;link link-external&quot;&gt;Jake Trent's blog post &lt;em&gt;Fallback Ref in React&lt;/em&gt;&lt;/a&gt;.
It introduced me to the &lt;code&gt;useImperativeHandle&lt;/code&gt; hook
and has good musings about why the hook is &lt;em&gt;lame&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;merge-refs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#merge-refs&quot;&gt;Merge refs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use a &lt;a href=&quot;https://github.com/gregberge/react-merge-refs&quot; class=&quot;link link-external&quot;&gt;utility like &lt;code&gt;react-merge-refs&lt;/code&gt;&lt;/a&gt; to merge the two refs:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; mergeRefs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react-merge-refs'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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;mergeRefs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;forwardedRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ref&lt;span class=&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&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood &lt;code&gt;mergeRefs&lt;/code&gt; returns a &lt;a href=&quot;https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node&quot; class=&quot;link link-external&quot;&gt;callback ref&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mergeRefs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;refs&lt;/span&gt;&lt;span class=&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 punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&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;
    refs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ref&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; ref &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&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 function&quot;&gt;ref&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;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ref &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
      &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;forwardedRef&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;,
&lt;code&gt;mergeRefs&lt;/code&gt; simply skips it.&lt;/p&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;More versatile because supports merging more than two refs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requires a 3rd party library
unless you re-implement the utility yourself.
And if you are going to re-implement it yourself,
there are simpler solutions (unless you need to merge more than two refs).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/theKashey/use-callback-ref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;use-callback-ref&lt;/code&gt; library&lt;/a&gt;
provides a similar &lt;code&gt;mergeRefs&lt;/code&gt; function
as well as a &lt;code&gt;useMergeRefs&lt;/code&gt; hook.&lt;/p&gt;
&lt;h2 id=&quot;which-solution-to-use&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#which-solution-to-use&quot;&gt;Which solution to use?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you need to merge more than two refs,
use a utility like &lt;a href=&quot;https://github.com/gregberge/react-merge-refs&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;react-merge-refs&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://github.com/theKashey/use-callback-ref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;use-callback-ref&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Otherwise I would prefer the first or the second solution.
Both are simple and straightforward.
No point in installing a dependency if you just want to create a fallback ref.&lt;/p&gt;
&lt;p&gt;Initially the &lt;code&gt;useImperativeHandle&lt;/code&gt; solution felt the most correct to me
because the hook is designed for customizing the value of the forwarded ref.
However, the solution is more difficult to understand
because the hook is so exotic and rarely used.&lt;/p&gt;
&lt;p&gt;One more point to consider:
what if,
during the lifecycle of &lt;code&gt;Child&lt;/code&gt; (the component wrapped in &lt;code&gt;React.forwardRef&lt;/code&gt;),
&lt;code&gt;forwardedRef&lt;/code&gt; is sometimes &lt;code&gt;null&lt;/code&gt; and sometimes a ref object?
I haven't tested how the different solutions would react to that.
This might or might not be relevant in your case.&lt;/p&gt;
&lt;h2 id=&quot;invalid-solutions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#invalid-solutions&quot;&gt;Invalid solutions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Knowing what &lt;em&gt;doesn't&lt;/em&gt; work can be very useful as well.&lt;/p&gt;
&lt;h3 id=&quot;conditional-useref&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#conditional-useref&quot;&gt;Conditional &lt;code&gt;useRef&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Creating a fallback ref with &lt;code&gt;useRef&lt;/code&gt; if &lt;code&gt;forwardedRef&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; might work:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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 comment&quot;&gt;// 🛑 Not allowed!&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Calling hooks conditionally breaks the rules of hooks.&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; forwardedRef &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;...but it might also not work
because calling hooks conditionally breaks the &lt;a href=&quot;https://reactjs.org/docs/hooks-rules.html&quot; class=&quot;link link-external&quot;&gt;rules of hooks&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;conditional-createref&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#conditional-createref&quot;&gt;Conditional &lt;code&gt;createRef&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactcreateref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;React.createRef&lt;/code&gt;&lt;/a&gt; is not a hook,
so it can be called conditionally:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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 comment&quot;&gt;// 🛑 A new ref is created on every re-render if `forwardedRef` is `null`&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; forwardedRef &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRef&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;However,
if &lt;code&gt;forwardedRef&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;,
a new ref is created every time the &lt;code&gt;Child&lt;/code&gt; component is re-rendered.&lt;/p&gt;
&lt;p&gt;Furthermore,
&lt;code&gt;ref&lt;/code&gt; is not stable,
so it needs to be included in the &lt;code&gt;useEffect&lt;/code&gt;'s dependency array.
Because of this, the &lt;code&gt;useEffect&lt;/code&gt; will run on every re-render.&lt;/p&gt;
&lt;p&gt;Omitting &lt;code&gt;ref&lt;/code&gt; from the dependency array
and ignoring the &amp;quot;exhaustive-deps&amp;quot; ESLint rule
is not a proper solution.
Ignoring the rule is confusing and opens the door for further problems.&lt;/p&gt;
&lt;h3 id=&quot;useref-conditional-createref&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#useref-conditional-createref&quot;&gt;&lt;code&gt;useRef&lt;/code&gt; + conditional &lt;code&gt;createRef&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To make the &lt;code&gt;ref&lt;/code&gt; from the previous invalid solution stable,
we can wrap it in another &lt;code&gt;useRef&lt;/code&gt;
and immediately grab its current value (i.e. &lt;code&gt;forwardedRef&lt;/code&gt; or the newly-created ref):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forwardRef&lt;/span&gt;&lt;span class=&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;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forwardedRef&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 comment&quot;&gt;// 🛑 A new ref is created and discarded on every re-render if `forwardedRef` is `null`&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forwardedRef &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRef&lt;/span&gt;&lt;span class=&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;current

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&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;ref&lt;span class=&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;// `ref` must be included here but is stable&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;However,
if &lt;code&gt;forwardedRef&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;,
a new ref is still created every time the &lt;code&gt;Child&lt;/code&gt; component is re-rendered;
it's just discarded immediately.&lt;/p&gt;
&lt;p&gt;Plus the code looks ugly and unclear.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This blog post contains these links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jaketrent.com/post/fallback-ref-react&quot; class=&quot;link link-external&quot;&gt;Jake Trent's blog post &lt;em&gt;Fallback Ref in React&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/search?q=react%20fallback%20ref&quot; class=&quot;link link-external&quot;&gt;Searching &amp;quot;react fallback ref&amp;quot; on npmjs.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Projects on GitHub:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gregberge/react-merge-refs&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;react-merge-refs&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/theKashey/use-callback-ref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;use-callback-ref&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brunoscopelliti/use-forward-ref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;use-forward-ref&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;React docs:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node&quot; class=&quot;link link-external&quot;&gt;Callback refs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/forwarding-refs.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Forwarding Refs&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#lazy-initial-state&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Lazy initial state&lt;/em&gt; (&lt;code&gt;useState&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactcreateref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;React.createRef&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactforwardref&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;React.forwardRef&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-rules.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Rules of Hooks&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#useimperativehandle&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;useImperativeHandle&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/2-way-sync/</id><title>Software for syncing internal and external hard drives</title><link href="https://mtsknn.fi/blog/2-way-sync/" /><published>2022-10-15T12:00:00+03:00</published><updated>2022-10-15T12:00:00+03:00</updated><category term="Cool tools"></category><content type="html">&lt;p&gt;I'm looking for a software that does 2-way syncing
between my MacBook's hard drive and an external hard drive.
Syncthing vs rsync vs Unison vs FreeFileSync vs Resilio Sync...
oh my!&lt;/p&gt;
&lt;h2 id=&quot;my-use-case&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#my-use-case&quot;&gt;My use case&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problem&quot;&gt;Problem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I have important files (photos and such)
scattered on three computers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A MacBook that I started using 9 months ago.&lt;/li&gt;
&lt;li&gt;A Lenovo laptop (Windows)
that I stopped using 9 months ago
because I switched to the MacBook.&lt;/li&gt;
&lt;li&gt;A custom-built desktop computer (Windows)
that I stopped using 27 months ago
because I switched to the Lenovo laptop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's a mess!
And I don't have back-ups. 🙈&lt;/p&gt;
&lt;h3 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I want to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copy important files on my current computer
to an external hard drive.&lt;/li&gt;
&lt;li&gt;Copy/move important files on the two older computers
to the same external hard drive.&lt;/li&gt;
&lt;li&gt;Sync the external hard drive and my current computer's hard drive.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This way I'll have two copies of every important file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One copy on my current computer's hard drive.&lt;/li&gt;
&lt;li&gt;Another copy on my external hard drive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's a good start!&lt;/p&gt;
&lt;p&gt;For this I'll need a software that does 2-way syncing.&lt;/p&gt;
&lt;h2 id=&quot;comparing-software&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#comparing-software&quot;&gt;Comparing software&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;syncthing-nope&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#syncthing-nope&quot;&gt;Syncthing – nope&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I have never used &lt;a href=&quot;https://syncthing.net/&quot; class=&quot;link link-external&quot;&gt;Syncthing&lt;/a&gt;,
but I have heard it's good.
Kinda like Dropbox:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Syncthing is a continuous file synchronization program.
It synchronizes files between two or more computers in real time [...].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But Syncthing doesn't satisfy my needs at this point.
&lt;a href=&quot;https://docs.syncthing.net/users/faq.html#does-syncthing-support-syncing-between-folders-on-the-same-system&quot; class=&quot;link link-external&quot;&gt;From Syncthing's FAQ&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Does Syncthing support syncing between folders on the same system?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No.
Syncthing is not designed to sync locally
and the overhead involved in doing so using Syncthing's method would be wasteful.
There are better programs to achieve this
such as &lt;a href=&quot;https://rsync.samba.org/&quot; class=&quot;link link-external&quot;&gt;rsync&lt;/a&gt;
or &lt;a href=&quot;https://www.cis.upenn.edu/~bcpierce/unison&quot; class=&quot;link link-external&quot;&gt;Unison&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; nope, can't use Syncthing in my case.&lt;/p&gt;
&lt;h3 id=&quot;rsync-nope&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#rsync-nope&quot;&gt;rsync – nope&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Quick googling reveals that
&lt;a href=&quot;https://stackoverflow.com/q/2936627/1079869&quot; class=&quot;link link-external&quot;&gt;rsync doesn't support 2-way syncing&lt;/a&gt;.
Or at least not in a straightforward way,
and I'd like a simple solution for now.&lt;/p&gt;
&lt;p&gt;I need 2-way syncing
because if I add files to the external hard drive from my old computers,
I want the new files to be synced/copied to my current computer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; nope, can't use rsync in my case.&lt;/p&gt;
&lt;h3 id=&quot;unison-maybe&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#unison-maybe&quot;&gt;Unison – maybe&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cis.upenn.edu/~bcpierce/unison&quot; class=&quot;link link-external&quot;&gt;Unison&lt;/a&gt;
was mentioned in Syncthing's FAQ
and in the Stack Overflow page about rsync.
And it indeed looks promising:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supports 2-way sync.&lt;/li&gt;
&lt;li&gt;Supports syncing between two (or more) folders on the same system.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=28863974&quot; class=&quot;link link-external&quot;&gt;Unison can be used with a daemon or cron&lt;/a&gt;,
making future syncs automatic and easy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One caveat that I came across with:
&lt;a href=&quot;https://news.ycombinator.com/item?id=20632727&quot; class=&quot;link link-external&quot;&gt;Unison can't run on a &amp;quot;heterogeneous network.&amp;quot;&lt;/a&gt;
In other words,
Unison binaries on your different devices must be
&lt;a href=&quot;https://news.ycombinator.com/item?id=23540837&quot; class=&quot;link link-external&quot;&gt;&amp;quot;exactly the same version, compiled with exactly the same version of various libraries,&amp;quot;&lt;/a&gt;
or you'll run into problems.
This caveat doesn't apply to me for now
since I would be installing Unison only to my current computer,
but this is good to know
and makes me wary of using Unison
(what if I would later like to install it on another device?).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; Unison might fit the bill, but is there anything better?&lt;/p&gt;
&lt;h3 id=&quot;freefilesync-my-choice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#freefilesync-my-choice&quot;&gt;FreeFileSync – my choice&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://freefilesync.org/&quot; class=&quot;link link-external&quot;&gt;FreeFileSync&lt;/a&gt; apparently works quite much like Unison.&lt;/p&gt;
&lt;p&gt;I found someone saying on Hacker News that
&lt;a href=&quot;https://news.ycombinator.com/item?id=29662838&quot; class=&quot;link link-external&quot;&gt;FreeFileSync has better GUI than Unison&lt;/a&gt;.
Since googling &amp;quot;FreeFileSync vs Unison&amp;quot; doesn't yield many results,
I might go ahead and trust that single internet stranger's word about the GUI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; FreeFileSync should fit the bill and might be better than Unison.&lt;/p&gt;
&lt;h3 id=&quot;resilio-sync-costs-money&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#resilio-sync-costs-money&quot;&gt;Resilio Sync – costs money&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.resilio.com/individuals/&quot; class=&quot;link link-external&quot;&gt;Resilio Sync&lt;/a&gt;
is a &amp;quot;fast, reliable, and simple file sync and share solution,
powered by P2P technology.&amp;quot;&lt;/p&gt;
&lt;p&gt;The Home edition costs $59.90 (one-time payment).
That's not much,
but I don't want to spend money on a syncing solution (at least not yet),
so I'll skip Resilio Sync for now.
(I don't even know if Resilio Sync would fit my needs.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; Resilio Sync costs money, so I won't even consider it for now.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#next-steps&quot;&gt;Next steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All right,
&lt;a href=&quot;https://freefilesync.org/&quot; class=&quot;link link-external&quot;&gt;FreeFileSync&lt;/a&gt; is my choice.&lt;/p&gt;
&lt;p&gt;After I have used it to have two copies of my important files,
I want to:&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Periodically (or preferably automatically)
sync my current computer's hard drive and the external hard drive.&lt;/li&gt;
&lt;li&gt;Periodically (or preferably automatically)
back up the files to an off-site location,
e.g. to &lt;a href=&quot;https://www.backblaze.com/b2/cloud-storage.html&quot; class=&quot;link link-external&quot;&gt;Backblaze B2&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This way I'll satisfy the 3-2-1 back-up strategy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have at least 3 copies of data&lt;/li&gt;
&lt;li&gt;with 2 of the copies on different local devices&lt;/li&gt;
&lt;li&gt;and 1 copy in an off-site location.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But I'm getting ahead of myself...
I should start by installing FreeFileSync.&lt;/p&gt;
&lt;p&gt;Oh, but how about buying an external hard drive?
Yeah, I've already got one –
I bought it 3 years ago for this purpose
but haven't even unboxed it yet. 🤡&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/git-stash-unstaged/</id><title>Stashing only unstaged changes in Git</title><link href="https://mtsknn.fi/blog/git-stash-unstaged/" /><published>2022-10-12T12:00:00+03:00</published><updated>2022-10-12T12:00:00+03:00</updated><category term="Git"></category><content type="html">&lt;p&gt;&lt;code&gt;git stash -k&lt;/code&gt; doesn't work as expected.
Use a temporary commit instead.&lt;/p&gt;
&lt;h2 id=&quot;non-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#non-solution&quot;&gt;Non-solution&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; stash -k  &lt;span class=&quot;token comment&quot;&gt;# -k = --keep-index&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What this does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keeps the staged changes: nice.&lt;/li&gt;
&lt;li&gt;Stashes unstaged &lt;em&gt;and staged&lt;/em&gt; changes:
not nice since the stash entry will also contain the staged changes.
This can be problematic
as (in this blog post) we want to stash only unstaged changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using &lt;a href=&quot;https://github.com/mtsknn/dotfiles/blob/master/.gitconfig&quot; class=&quot;link link-external&quot;&gt;my Git aliases&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git c -m wip&lt;/code&gt; to create a temporary commit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash&lt;/code&gt; to stash the remaining (unstaged/uncommitted) changes
&lt;ul&gt;
&lt;li&gt;Optionally use &lt;code&gt;-u&lt;/code&gt; (= &lt;code&gt;--include-untracked&lt;/code&gt;) to also stash untracked files&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git undo&lt;/code&gt; to &lt;a href=&quot;/blog/how-to-undo-the-last-previous-most-recent-commit-in-git/&quot; class=&quot;link&quot;&gt;undo the previous commit&lt;/a&gt;
(the temporary commit done in step 1)
&lt;ul&gt;
&lt;li&gt;Optionally use &lt;code&gt;--soft&lt;/code&gt; to keep the changes in the staging area&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If not using my Git aliases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git c&lt;/code&gt; = &lt;code&gt;git commit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git undo&lt;/code&gt; = &lt;code&gt;git reset HEAD~&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Source of the solution:
&lt;a href=&quot;https://stackoverflow.com/a/34681302/1079869&quot; class=&quot;link link-external&quot;&gt;Stephen Hanson's answer on Stack Overflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My point is that my Git aliases make the solution even nicer,
especially &lt;code&gt;git undo&lt;/code&gt; since I can't remember the underlying command,
plus &lt;code&gt;git reset&lt;/code&gt; is scary (but the alias makes it less scary).&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/coin-combinations-puzzle/</id><title>JS solutions to the &quot;coin combinations&quot; interview puzzle</title><link href="https://mtsknn.fi/blog/coin-combinations-puzzle/" /><published>2022-10-10T12:00:00+03:00</published><updated>2022-10-10T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;&amp;quot;Given an array of coins and a target amount,
return all combinations of coins that add up to the amount,
or an empty array if no such combinations exist.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;example-inputs-and-outputs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-inputs-and-outputs&quot;&gt;Example inputs and outputs&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; coins &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 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;2&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 number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; amount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getCoinCombinations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [[1, 1, 5, 5],  [1, 1, 10],  [2, 5, 5],  [2, 10]]&lt;/span&gt;

coins &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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
amount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getCoinCombinations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; []&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A slight variation to the puzzle is to return only one valid combination:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; coins &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 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;2&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 number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; amount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getCoinCombination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Any of the following is valid:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 1, 5, 5]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 1, 10]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [2, 5, 5]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [2, 10]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's solve both puzzles.&lt;/p&gt;
&lt;h2 id=&quot;why-though&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-though&quot;&gt;Why though&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It was fun to solve this!&lt;/p&gt;
&lt;h2 id=&quot;initial-naive-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#initial-naive-solution&quot;&gt;Initial naive solution&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Find all possible coin combinations.
&lt;ul&gt;
&lt;li&gt;I have a separate post for that:
&lt;a href=&quot;/blog/js-array-item-combinations/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Generating array permutations of all lengths in JS&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Filter out the combinations whose sum doesn't match the target amount.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;getting-all-combinations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#getting-all-combinations&quot;&gt;Getting all combinations&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; coins &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 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;2&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 number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&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; amount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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 function&quot;&gt;getCombinations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coins&lt;span class=&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;combo&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 function&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&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 function-variable function&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;numbers&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; numbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&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 comment&quot;&gt;// Via https://mtsknn.fi/blog/js-array-item-combinations/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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;
  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newCombos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;newCombos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; combos
  &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;getting-a-single-combination&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#getting-a-single-combination&quot;&gt;Getting a single combination&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Change &lt;code&gt;.filter()&lt;/code&gt; to &lt;code&gt;.find()&lt;/code&gt; and fall back to an empty array:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombination&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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 function&quot;&gt;getCombinations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coins&lt;span class=&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;find&lt;/span&gt;&lt;span class=&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;combo&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 function&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;why-this-is-nice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-this-is-nice&quot;&gt;Why this is nice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Straightforward and simple.&lt;/li&gt;
&lt;li&gt;No boring &lt;code&gt;for&lt;/code&gt; loops.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-this-is-naive&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-this-is-naive&quot;&gt;Why this is naive&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;First all combinations are generated,
then they are looped through again to find matching combinations.
This is inefficient,
especially when getting only a single combination.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If &lt;code&gt;coins&lt;/code&gt; is a large array (19+ items),
&lt;code&gt;getCombinations()&lt;/code&gt; gets very slow
because the amount of total combinations (before filtering) will be &lt;em&gt;huge&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;At some point (32+ coins) the code won't even work anymore
because the unfiltered combinations won't fit in a single array.&lt;/p&gt;
&lt;p&gt;More details in a separate post:
&lt;a href=&quot;/blog/js-array-item-combinations-part-2/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Finding array item combinations for large arrays is complex&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When looping through the combinations to find matching combinations,
each combination's sum is calculated.
The sums could be calculated earlier to avoid having to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;loop through them again (in the &lt;code&gt;filter()&lt;/code&gt; or &lt;code&gt;find()&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;keep invalid combinations around.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;better-solution-for-getting-all-combinations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#better-solution-for-getting-all-combinations&quot;&gt;Better solution for getting all combinations&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;starting-point&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#starting-point&quot;&gt;Starting point&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here's the initial solution
but without the separate &lt;code&gt;getCombinations&lt;/code&gt; function:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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;
  coins
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&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; newCombos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;coin&lt;span class=&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;newCombos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; combos
    &lt;span class=&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 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;combo&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 function&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&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 function-variable function&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;numbers&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; numbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-1&quot;&gt;Step 1&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each combination in &lt;code&gt;combos&lt;/code&gt; is an array of numbers (coins),
and each combination's sum is calculated in the filter method.&lt;/p&gt;
&lt;p&gt;If the sums were calculated already in the reducer,
there would be no need to loop through each combination's coins in the filter method.&lt;/p&gt;
&lt;p&gt;This can be done by making each combination an object,
like &lt;code&gt;{ coins: [1, 2, 1, 5], sum: 9 }&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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;
  coins
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&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; newCombos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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 punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;coins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; coin&lt;span class=&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;

      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;coins&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;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; coin&lt;span class=&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;newCombos
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; combos
    &lt;span class=&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 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;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There's a new mapper function at the end,
but we'll deal with that soon.&lt;/p&gt;
&lt;h3 id=&quot;step-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-2&quot;&gt;Step 2&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Does every combination need to be stored in &lt;code&gt;combos&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All coins: 1, 2, 1, 5, 5, 10.&lt;/li&gt;
&lt;li&gt;Target amount is 12.&lt;/li&gt;
&lt;li&gt;Current coin is the second last coin (value 5).&lt;/li&gt;
&lt;li&gt;A previous combination has the coins 1, 2, 1 and 5 (→ sum 9).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Question:&lt;/strong&gt;
Does it make sense to create a new combination
by adding the current coin (5) to the previous combination's coins?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Answer:&lt;/strong&gt;
The new combination's sum would be 14,
which is greater than the target amount (12),
so no:
creating that combination wouldn't make sense.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Changing &lt;code&gt;combos.map()&lt;/code&gt; to &lt;code&gt;combos.forEach()&lt;/code&gt;
allows conditionally pushing one valid combination at a time to &lt;code&gt;combos&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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;
  coins
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&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;
      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; newSum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; coin
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newSum &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;coins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newSum&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;coins&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;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; coin&lt;span class=&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;return&lt;/span&gt; combos
    &lt;span class=&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 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;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There's some duplication
(the codes inside &lt;code&gt;combos.forEach()&lt;/code&gt; and below it look very similar),
but we'll deal with that soon.&lt;/p&gt;
&lt;h3 id=&quot;step-3&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-3&quot;&gt;Step 3&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;combos&lt;/code&gt; contains both incomplete combinations like &lt;code&gt;[2, 5]&lt;/code&gt; (sum 7)
and complete combinations like &lt;code&gt;[2, 5, 5]&lt;/code&gt; (sum 12).&lt;/p&gt;
&lt;p&gt;If incomplete and complete combinations were stored separately,
the filtering after the reducer would be unnecessary.&lt;/p&gt;
&lt;p&gt;This can be done by changing the accumulator array (&lt;code&gt;combos&lt;/code&gt;)
to an object that contains two arrays (&lt;code&gt;{ complete: [], incomplete: [] }&lt;/code&gt;).
No need to store sums of the complete combinations (the sums should be equal to &lt;code&gt;amount&lt;/code&gt;),
so no need for the mapper function after the reducer either:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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;
  coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&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;
      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;incomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; newSum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; coin

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newSum &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; amount&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 keyword&quot;&gt;const&lt;/span&gt; newCoins &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newSum &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newCoins&lt;span class=&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;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;incomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;coins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newCoins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newSum&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;coin&lt;span class=&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;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;incomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;coins&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;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; coin&lt;span class=&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;return&lt;/span&gt; combos
    &lt;span class=&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;complete&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 literal-property property&quot;&gt;incomplete&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complete
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-4&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-4&quot;&gt;Step 4&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Final step is to reduce duplication:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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; coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&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;
      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;incomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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 function&quot;&gt;keepComboIfValid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; coin&lt;span class=&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;keepComboIfValid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combos&lt;span class=&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; coin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; combos
    &lt;span class=&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;complete&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 literal-property property&quot;&gt;incomplete&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complete

  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;keepComboIfValid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; previousCoins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sum&lt;/span&gt;&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; amount&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 keyword&quot;&gt;const&lt;/span&gt; newCoins &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; previousCoins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newCoins&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;incomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;coins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newCoins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sum &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;keepComboIfValid&lt;/code&gt; mutates the reducer function's accumulator object.
But I think that's OK
because the mutations are restricted to the &lt;code&gt;getCoinCombinations&lt;/code&gt; function,
so the mutations are still &lt;em&gt;local&lt;/em&gt;.
Related blog post:
&lt;a href=&quot;/blog/local-mutations/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Local mutations are all right&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Potential misstep&lt;/h4&gt;
&lt;p&gt;It would be tempting to simplify the &lt;code&gt;keepComboIfValid&lt;/code&gt; function like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ⛔️ Nope&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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; coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coin&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;
      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;incomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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 function&quot;&gt;keepComboIfValid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combos&lt;span class=&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;coins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; coin&lt;span class=&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 function&quot;&gt;keepComboIfValid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combos&lt;span class=&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;coins&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;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; coin &lt;span class=&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; combos
    &lt;span class=&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;complete&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 literal-property property&quot;&gt;incomplete&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complete

  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;keepComboIfValid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; combo&lt;/span&gt;&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;incomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this would be less efficient
because new combinations are generated
and then immediately discarded if they are not valid.&lt;/p&gt;
&lt;h2 id=&quot;better-solution-for-getting-a-single-combination&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#better-solution-for-getting-a-single-combination&quot;&gt;Better solution for getting a single combination&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Similar to the previous code,
but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No need to store complete combinations in an array;
we want to return the first complete combination immediately when it's found.&lt;/li&gt;
&lt;li&gt;A reducer function can't be terminated early,
so we need to use &lt;code&gt;for&lt;/code&gt; loops instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCoinCombination&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&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; incompleteCombos &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 keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; coin &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; coins&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&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;coin&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 punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; length &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; incompleteCombos&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&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 keyword&quot;&gt;const&lt;/span&gt; combo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; incompleteCombos&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newSum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; coin
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newSum &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newCoins &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newSum &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; newCoins
      incompleteCombos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;coins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newCoins&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newSum &lt;span class=&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;

    incompleteCombos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;coins&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;coin&lt;span class=&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;sum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; coin &lt;span class=&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;return&lt;/span&gt; &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;potential-misstep&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#potential-misstep&quot;&gt;Potential misstep&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These wouldn't work for the inner &lt;code&gt;for&lt;/code&gt; loop
because we are pushing to &lt;code&gt;incompleteCombos&lt;/code&gt; inside the loop:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; combo &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; incompleteCombos&lt;span class=&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 punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; incompleteCombos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both of these would process the newly-pushed combinations,
which would be incorrect.&lt;/p&gt;
&lt;p&gt;So, the length of &lt;code&gt;incompleteCombos&lt;/code&gt; needs to be stored at the beginning of the looping.
These two are effectively the same,
the second one is just trying to be clever:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; length &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; incompleteCombos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&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 keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; length &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; incompleteCombos&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&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&gt;&lt;/code&gt;&lt;/pre&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/local-mutations/</id><title>Local mutations are all right</title><link href="https://mtsknn.fi/blog/local-mutations/" /><published>2022-10-04T12:00:00+03:00</published><updated>2022-10-04T12:00:00+03:00</updated><category term="Clean code"></category><category term="JavaScript"></category><content type="html">&lt;p&gt;For example,
mutating a reducer function's accumulator array can be better
than religiously avoiding mutations and returning only new arrays from the reducer.&lt;/p&gt;
&lt;h2 id=&quot;example-of-a-mutating-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-of-a-mutating-code&quot;&gt;Example of a mutating code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recently published a blog post about
&lt;a href=&quot;/blog/js-array-item-combinations/&quot; class=&quot;link&quot;&gt;how to find all possible combinations of array items in JS&lt;/a&gt;.
Here's the code:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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;
  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newCombos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;newCombos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; combos
  &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how I'm mutating the accumulator array (&lt;code&gt;combos&lt;/code&gt;) in the reducer function
by pushing items to it?
Gasp!&lt;/p&gt;
&lt;p&gt;Mutations can easily lead to confusing code.
However, not all mutations are bad.&lt;/p&gt;
&lt;p&gt;In this case,
the mutations are &lt;em&gt;local&lt;/em&gt; –
mutations of &lt;code&gt;combos&lt;/code&gt; happen only inside the reducer function.
Keeping track (mentally) of the mutations is easy.&lt;/p&gt;
&lt;h2 id=&quot;avoiding-that-mutation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#avoiding-that-mutation&quot;&gt;Avoiding that mutation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The mutations &lt;em&gt;could&lt;/em&gt; be avoided e.g. like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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;
  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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;
      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look ma, no mutation!
(&lt;code&gt;combos.concat()&lt;/code&gt; returns a new array instead of mutating the existing array.)&lt;/p&gt;
&lt;p&gt;Or like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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;
  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But both non-mutating versions are actually horrible:&lt;/p&gt;
&lt;h3 id=&quot;inefficient&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#inefficient&quot;&gt;Inefficient&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A new accumulator array is created on each iteration.
It doesn't matter with short input arrays,
but it &lt;em&gt;does&lt;/em&gt; matter with longer input arrays.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/mtsknn/advent-of-code/blob/master/2015/03.md&quot; class=&quot;link link-external&quot;&gt;my solution to the Advent of Code 2015/03 puzzle&lt;/a&gt;,
I found that using the spread syntax made my code &lt;em&gt;a hundred times slower&lt;/em&gt; (on my machine)
compared to mutating the accumulator array –
10ms vs 1,000ms.
(&lt;a href=&quot;https://adventofcode.com/&quot; class=&quot;link link-external&quot;&gt;Advent of Code puzzles&lt;/a&gt; typically have large inputs.)&lt;/p&gt;
&lt;h3 id=&quot;less-readable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#less-readable&quot;&gt;Less readable&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the first version (using &lt;code&gt;combos.concat()&lt;/code&gt;),
it's difficult to see at a glance what the non-mutating one-liner is doing.&lt;/p&gt;
&lt;p&gt;Prettier also insists on formatting the reducer function's body on a single line.
The following would be clearer (but still not as clear as the non-mutating version):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCombinations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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;
  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 comment&quot;&gt;// prettier-ignore&lt;/span&gt;
      combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;combos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;combo&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; combo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second version (no &lt;code&gt;combos.concat()&lt;/code&gt;) is better
but still not great (debatable, I guess).&lt;/p&gt;
&lt;h3 id=&quot;unnecessary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#unnecessary&quot;&gt;Unnecessary&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The accumulator value is quite &lt;em&gt;meant&lt;/em&gt; to be mutated –
you create an array or an object to which you accumulate values on every iteration.&lt;/p&gt;
&lt;p&gt;Saying that the accumulator is meant to be mutated is a bold statement,
so I checked &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce&quot; class=&quot;link link-external&quot;&gt;what MDN says about array reducers in JS&lt;/a&gt;
(emphasis added by me):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;reduce()&lt;/code&gt; is a central concept in &lt;a href=&quot;https://en.wikipedia.org/wiki/Functional_programming&quot; class=&quot;link link-external&quot;&gt;functional programming&lt;/a&gt;,
where it's not possible to mutate any value,
so in order to accumulate all values in an array,
one must return a new accumulator value on every iteration.
&lt;strong&gt;This convention propagates to JavaScript's &lt;code&gt;reduce()&lt;/code&gt;:
you should use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax&quot; class=&quot;link link-external&quot;&gt;spreading&lt;/a&gt;
or other copying methods
where possible
to create new arrays and objects as the accumulator,
rather than mutating the existing one.&lt;/strong&gt; [...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Eh...
I respect the MDN docs,
but I don't buy that.
If you are aiming for maximum purity etc.,
then maybe yeah.
But I would prefer performance and clarity to a rigid functional programming mindset.&lt;/p&gt;
&lt;p&gt;I wanted more opinions (:D),
so I googled &amp;quot;js reduce mutate accumulator&amp;quot;
and found &lt;a href=&quot;https://stackoverflow.com/q/63727586/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Is mutating accumulator in reduce function considered bad practice?&lt;/em&gt; on Stack Overflow&lt;/a&gt;.
The currently highest-scored answer by &amp;quot;customcommander&amp;quot; has a nice summary:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It isn't [a bad practice] if you own the accumulator.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that's quite much what I mean by local mutations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you own the accumulator,
the mutations are local (restricted to the reducer function's scope)
and thus safe.&lt;/li&gt;
&lt;li&gt;If you don't own the accumulator –
if it's coming from elsewhere –
the mutations won't be local anymore,
so you need to be very careful with the mutations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the accumulator is coming from elsewhere,
it's easy to shallow-copy it to avoid non-local mutations:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; val&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 comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc
  &lt;span class=&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;objectComingFromElsewhere &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; val&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 comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc
  &lt;span class=&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;arrayComingFromElsewhere&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;But be wary of deep mutations,
or do a deep clone instead.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I'll conclude by quoting the last two paragraphs
of &lt;a href=&quot;https://gist.github.com/customcommander/97eb4b3f1600773db59406d39f3f9cd7&quot; class=&quot;link link-external&quot;&gt;a relevant article&lt;/a&gt;
by the author of the aforementioned Stack Overflow answer (two commas added by me for clarity):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Uncontrolled access to shared state can lead to complex bugs
which is why immutability is so dear to functional programmers.
However,
immutability isn't only achieved through the cloning of data,
in fact this is most likely to be a naive approach to it.
Immutability is a quality of a data structure,
not a process per se.&lt;/p&gt;
&lt;p&gt;In this particular case
the initial value of the reducing function is &lt;em&gt;safe&lt;/em&gt; to mutate.
The spread operator offers no additional protection against side effects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words:
local mutations are all right.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-array-item-combinations-part-2/</id><title>Generating permutations of large arrays is complex</title><link href="https://mtsknn.fi/blog/js-array-item-combinations-part-2/" /><published>2022-10-03T12:00:00+03:00</published><updated>2023-11-02T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;That's because it would take a very long time,
and at some point you would have so many permutations
that they wouldn't fit in an array.&lt;/p&gt;
&lt;h2 id=&quot;starting-point&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#starting-point&quot;&gt;Starting point&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By &amp;quot;array permutations&amp;quot; I'm referring to my blog post from yesterday:
&lt;a href=&quot;/blog/js-array-item-combinations/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Generating array permutations with all lengths in JS&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's the code:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getPermutations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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;
  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;permutations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newPermutations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;permutation&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;
      permutation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;newPermutations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; permutations
  &lt;span class=&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 function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [[1],  [2],  [1, 2],  [3],  [1, 3],  [2, 3],  [1, 2, 3]]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;rangeerrors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#rangeerrors&quot;&gt;RangeErrors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The code throws if the input array's length is too long.
In Firefox the limit is 20:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt; &lt;span class=&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;// OK&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt; &lt;span class=&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;// RangeError&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;In Firefox,
the error message is &amp;quot;too many function arguments.&amp;quot;&lt;/li&gt;
&lt;li&gt;In Chrome, Edge, Safari and Node.js,
the error message is &amp;quot;Maximum call stack size exceeded.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Firefox's error message seems more helpful
since the problem is that &lt;code&gt;permutations.push()&lt;/code&gt; is called with too many arguments.
In Firefox the limit is 500,000 items:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token 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;push&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 function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500_000&lt;/span&gt;&lt;span class=&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;// OK&lt;/span&gt;
&lt;span class=&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;push&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 function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500_001&lt;/span&gt;&lt;span class=&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;// RangeError&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;avoiding-rangeerrors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#avoiding-rangeerrors&quot;&gt;Avoiding RangeErrors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We could try to avoid the problem by avoiding the spread syntax altogether:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getPermutations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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 prefix unchanged&quot;&gt; &lt;/span&gt;  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;permutations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newPermutations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;permutation&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 prefix deleted&quot;&gt;-&lt;/span&gt;      permutation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;    permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;newPermutations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;permutation&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 prefix inserted&quot;&gt;+&lt;/span&gt;      permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permutation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&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 class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; permutations
&lt;span class=&quot;token prefix unchanged&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(I thought that this would also increase performance,
but it doesn't seem to.
Makes sense though:
we do avoid iterating through &lt;code&gt;newPermutations&lt;/code&gt; which is good,
but now we are calling &lt;code&gt;permutations.push()&lt;/code&gt; many more times with only one argument.)&lt;/p&gt;
&lt;h2 id=&quot;its-slow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#its-slow&quot;&gt;It's slow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now larger input arrays work,
but getting permutations for large input arrays is increasingly slow:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt; &lt;span class=&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~200ms (on my machine)&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt; &lt;span class=&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~400ms (on my machine)&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt; &lt;span class=&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~800ms (on my machine)&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;23&lt;/span&gt; &lt;span class=&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~1800ms (on my machine)&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; &lt;span class=&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~4200ms (on my machine)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ain't nobody got time to wait that long!&lt;/p&gt;
&lt;h2 id=&quot;the-input-arrays-length-is-still-limited&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-input-arrays-length-is-still-limited&quot;&gt;The input array's length is still limited&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Firefox,
the maximum length of an array seems to be &lt;code&gt;2 ** 32 - 1&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&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 comment&quot;&gt;// OK&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// RangeError: invalid array length&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The length of the array returned by &lt;code&gt;getPermutations(items)&lt;/code&gt;
is incidentally &lt;code&gt;2 ** items.length - 1&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&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 comment&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&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 comment&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&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;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&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 comment&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&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;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&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 comment&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt; &lt;span class=&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;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&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 comment&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...and so on&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href=&quot;https://math.stackexchange.com/q/1117236/18013&quot; class=&quot;link link-external&quot;&gt;Math for calculating the total number of permutations.&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;In other words,
the maximum length of the input array is 32.&lt;/p&gt;
&lt;p&gt;But input arrays that long would be impractical
since getting all permutations would take way too long.
Plus there would be quite many permutations:
&lt;code&gt;2 ** 32 - 1&lt;/code&gt; = 4,294,967,295.
Over 4 billion!&lt;/p&gt;
&lt;h2 id=&quot;think-of-alternatives&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#think-of-alternatives&quot;&gt;Think of alternatives&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Okay,
so the input array's length is limited to 32 (in Firefox at least),
and getting all permutations would take a very long time,
so think:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do you need to generate all permutations?&lt;/li&gt;
&lt;li&gt;Do you need to retain all permutations?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some pointers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you only need permutations that are e.g. 2 or 3 items long,
there's no point in generating longer permutations.&lt;/li&gt;
&lt;li&gt;If you are looking for a single permutation that matches a certain criterion,
terminate the process after finding your solution.
&lt;ul&gt;
&lt;li&gt;Not possible if using an array reducer;
use &lt;code&gt;for&lt;/code&gt; loops and the &lt;code&gt;break&lt;/code&gt; statement instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you are looking for multiple permutations that match a certain criterion,
skip non-matching permutations early,
i.e. don't store them in the accumulator array.
&lt;ul&gt;
&lt;li&gt;Example:
&lt;a href=&quot;/blog/coin-combinations-puzzle/&quot; class=&quot;link&quot;&gt;&lt;em&gt;JS solutions to the &amp;quot;coin combinations&amp;quot; interview puzzle&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I don't remember if I have ever used generator functions,
but this could be a good use case for them.
I got this idea from &lt;a href=&quot;https://evanhahn.com/nested-list-permutations-in-javascript/&quot; class=&quot;link link-external&quot;&gt;Evan Hahn's blog post &lt;em&gt;Nested array permutations in JavaScript&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-array-item-combinations/</id><title>Generating array permutations of all lengths in JS</title><link href="https://mtsknn.fi/blog/js-array-item-combinations/" /><published>2022-10-02T12:00:00+03:00</published><updated>2023-05-01T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Example:
converting &lt;code&gt;[1, 2, 3]&lt;/code&gt;
into &lt;code&gt;[[1],  [2],  [1, 2],  [3],  [1, 3],  [2, 3],  [1, 2, 3]]&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why&quot;&gt;Why?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recall needing this a few times,
maybe when solving &lt;a href=&quot;https://adventofcode.com/&quot; class=&quot;link link-external&quot;&gt;Advent of Code puzzles&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Plus I really like my solution.
I find it straightforward,
maybe even obvious now.
But it took me a while to come up with it –
my first attempts were much more complex and didn't even work properly –
and maybe that's why I'm keen on this simple solution.&lt;/p&gt;
&lt;h2 id=&quot;example-input-and-output&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-input-and-output&quot;&gt;Example input and output&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; array &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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/* =&gt;
  [
    [1],
    [2],
    [1, 2],
    [3],
    [1, 3],
    [2, 3],
    [1, 2, 3],
    [4],
    [1, 4],
    [2, 4],
    [1, 2, 4],
    [3, 4],
    [1, 3, 4],
    [2, 3, 4],
    [1, 2, 3, 4],
  ]
*/&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#code&quot;&gt;Code&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getPermutations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&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;
  items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;permutations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newPermutations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;permutation&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;
      permutation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;newPermutations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    returnpermutations
  &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Probably not the most efficient solution,
but straightforward and easy.
And no &lt;code&gt;for&lt;/code&gt; loops!&lt;/p&gt;
&lt;h2 id=&quot;order-of-permutations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#order-of-permutations&quot;&gt;Order of permutations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The order of the final permutations change
if you change the order of the &lt;code&gt;push&lt;/code&gt; method's arguments:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;permutations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newPermutations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;permutations&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;
    permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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;newPermutations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; permutations
&lt;span class=&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;//=&gt; [[1],  [2],  [1, 2],  [3],  [1, 3],  [2, 3],  [1, 2, 3]]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// versus&lt;/span&gt;

items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;permutations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newPermutations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;permutations&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;
    permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  permutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;newPermutations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&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; permutations
&lt;span class=&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;//=&gt; [[1],  [1, 2],  [2],  [1, 3],  [1, 2, 3],  [2, 3],  [3]]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In some cases the order might matter.&lt;/p&gt;
&lt;h2 id=&quot;beware-too-large-input-arrays&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#beware-too-large-input-arrays&quot;&gt;Beware too large input arrays&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The code doesn't work if the input array's length is 20+:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt; &lt;span class=&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;// OK&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt; &lt;span class=&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;// RangeError&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More details in Part 2:
&lt;a href=&quot;/blog/js-array-item-combinations-part-2&quot; class=&quot;link&quot;&gt;&lt;em&gt;Generating permutations of large arrays is complex&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mutation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#mutation&quot;&gt;Mutation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Notice how I'm mutating the accumulator array (&lt;code&gt;permutations&lt;/code&gt;)
in the reducer function?&lt;/p&gt;
&lt;p&gt;Mutations can be bad,
but in this case they are okay,
because &lt;a href=&quot;/blog/local-mutations/&quot; class=&quot;link&quot;&gt;local mutations are all right&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/unreplied/</id><title>I want a chat app with an &quot;unreplied&quot; message state</title><link href="https://mtsknn.fi/blog/unreplied/" /><published>2022-09-28T12:00:00+03:00</published><updated>2022-09-28T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;Most chat apps have an &amp;quot;unread&amp;quot; message state
to keep track of messages I haven't read yet.
Why isn't there a different state for messages I haven't replied to yet?&lt;/p&gt;
&lt;p&gt;I chat with &lt;a href=&quot;https://hanki.dev/&quot; class=&quot;link link-external&quot;&gt;my bro&lt;/a&gt; a lot.
We always have several conversations ongoing at the same time.&lt;/p&gt;
&lt;p&gt;We currently use Telegram,
so all messages are in a single big list.&lt;/p&gt;
&lt;p&gt;When replying to his messages,
I basically have two options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reply to all unreplied messages in a single session.
I don't like this because:
&lt;ul&gt;
&lt;li&gt;It would often take a very long times,
sometimes even several hours (like I said, we chat a lot!).&lt;/li&gt;
&lt;li&gt;Sometimes it's better to ponder things before replying.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Reply to some messages now and some messages later.
I don't like this because:
&lt;ul&gt;
&lt;li&gt;It gets very difficult to keep track of messages I have or haven't replied to.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And sometimes I want to start a new conversation
and not reply to any previous messages.
This alone makes keeping track of replied/unreplied messages difficult.&lt;/p&gt;
&lt;p&gt;We have previously tried a private Discord server with several channels –
one main topic per channel, e.g. &amp;quot;dev&amp;quot; or &amp;quot;health.&amp;quot;
Having several channels helps a bit, but the core problem is still the same:
it's difficult to keep track of replied/unreplied messages &lt;em&gt;in each channel&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;One level deep sub-threads (like on Discord or Slack) don't help either:
it's difficult to keep track of replied/unreplied messages &lt;em&gt;in each sub-thread&lt;/em&gt;.
Sub-threads might even make things more confusing.&lt;/p&gt;
&lt;p&gt;A tree-like message structure (like on Reddit or Hacker News) could help organize messages
because not all messages would be in a single big list (or several big lists if using channels),
but it wouldn't solve the problem of keeping track of replied/unreplied messages.
Plus maybe a tree-like structure would get in the way of quick, comfortable chatting.&lt;/p&gt;
&lt;p&gt;So here's what I want:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &amp;quot;unreplied&amp;quot; message state for keeping track of replied/unreplied messages.&lt;/li&gt;
&lt;li&gt;Threads for organizing messages by conversation.
&lt;ul&gt;
&lt;li&gt;New conversation = new thread.&lt;/li&gt;
&lt;li&gt;Flat threads (no nesting, i.e. no sub-threads or tree-like structure)
to keep things simple.&lt;/li&gt;
&lt;li&gt;Threads are superior to channels:
no need to think of the most suitable channel/topic for a new conversation;
just start a new thread.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Maybe I should create my own chat app. 🤷‍♂️&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/ltex/</id><title>LTeX: grammar/spell checker on steroids for VS Code</title><link href="https://mtsknn.fi/blog/ltex/" /><published>2022-09-20T12:00:00+03:00</published><updated>2022-09-20T12:00:00+03:00</updated><category term="Cool tools"></category><category term="English"></category><category term="VS Code"></category><content type="html">&lt;p&gt;Doesn't only look for typos
but for grammar and style issues as well.
Not to be confused with LaTeX.&lt;/p&gt;
&lt;h2 id=&quot;about-ltex&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#about-ltex&quot;&gt;About LTeX&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=valentjn.vscode-ltex&quot; class=&quot;link link-external&quot;&gt;LTeX&lt;/a&gt; is a grammar/spell checker for VS Code.
It uses &lt;a href=&quot;https://languagetool.org/&quot; class=&quot;link link-external&quot;&gt;LanguageTool&lt;/a&gt; under the hood
and supports LaTeX, Markdown and more.&lt;/p&gt;
&lt;p&gt;I have been using LTeX for half a year now.
It's great!&lt;/p&gt;
&lt;p&gt;Note that LTeX is not the same as &lt;a href=&quot;https://www.latex-project.org/&quot; class=&quot;link link-external&quot;&gt;LaTeX, the &amp;quot;document preparation system.&amp;quot;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=valentjn.vscode-ltex&quot; class=&quot;link link-external&quot;&gt;Check out the LTeX extension for VS Code&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;pros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pros&quot;&gt;Pros&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Checks for spelling issues (typos)&lt;/li&gt;
&lt;li&gt;Checks for grammar issues&lt;/li&gt;
&lt;li&gt;Checks for style issues
&lt;ul&gt;
&lt;li&gt;Example:
&lt;em&gt;&amp;quot;Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.&amp;quot;&lt;/em&gt;
I get this often when starting too many sentences with the word &amp;quot;I&amp;quot;
(maybe I love myself too much)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Explains why things are (or might be) wrong instead of just complaining&lt;/li&gt;
&lt;li&gt;Works offline&lt;/li&gt;
&lt;li&gt;Is privacy-friendly (because works offline)&lt;/li&gt;
&lt;li&gt;Is easy to set up:
install the VS Code extension
and the rest will be auto-installed&lt;/li&gt;
&lt;li&gt;Provides quick fixes (&lt;kbd&gt;Meta&lt;/kbd&gt;+&lt;kbd&gt;.&lt;/kbd&gt;)&lt;/li&gt;
&lt;li&gt;Doesn't slow down VS Code
(at least not on my machine;
some other spell checker extensions have been horribly slow)&lt;/li&gt;
&lt;li&gt;Works even if you split sentences to multiple lines
&lt;ul&gt;
&lt;li&gt;Related: &lt;a href=&quot;/blog/4-1-wrapping-styles-for-markdown-prose-and-code-comments/&quot; class=&quot;link&quot;&gt;&lt;em&gt;4 + 1 wrapping styles for Markdown prose and code comments&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cons&quot;&gt;Cons&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Doesn't support Finnish&lt;/li&gt;
&lt;li&gt;Doesn't support disabling checking for a single document/file
&lt;ul&gt;
&lt;li&gt;There's &lt;em&gt;&amp;quot;LTeX: Clear Diagnostics in Current Document&amp;quot;&lt;/em&gt;
in VS Code's Command Palette,
but the extension runs again when you type or erase even a single letter&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sometimes &lt;a href=&quot;https://github.com/valentjn/vscode-ltex/issues/497&quot; class=&quot;link link-external&quot;&gt;leaves stray Java processes behind&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;It might be a good idea to manually terminate the stray processes from time to time,
especially if you are low on RAM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/linen-bedclothes/</id><title>Linen bedclothes are the best</title><link href="https://mtsknn.fi/blog/linen-bedclothes/" /><published>2022-09-17T12:00:00+03:00</published><updated>2022-09-17T12:00:00+03:00</updated><category term="Sleep"></category><content type="html">&lt;p&gt;I recently switched from linen bedclothes (sheets, pillowcases, duvet covers)
back to cotton bedclothes –
bad idea.
My sleep quality took a drastic hit.&lt;/p&gt;
&lt;p&gt;Sometimes you notice the importance of something only after losing that thing.
This is such a case.&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I have been using linen bedclothes for almost two years.&lt;/p&gt;
&lt;p&gt;Recently I started using a second set of bedclothes to make laundry days easier –
no need to wash the bedclothes first thing in the morning if I have more than one set of bedclothes.&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;However, the second set of bedclothes is made of cotton.
I didn't remember how bad cotton bedclothes are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cotton doesn't breathe properly.&lt;/li&gt;
&lt;li&gt;Cotton feels &amp;quot;hard&amp;quot; (not soft).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's possible that not all cotton bedclothes are bad,
but mine are.&lt;/p&gt;
&lt;p&gt;Last night I slept again with my linen bedclothes – and boy are they &lt;em&gt;wonderful&lt;/em&gt;!
I'll ditch the cotton bedclothes as soon as I have ordered a second set of linen bedclothes
(so hopefully before next year).&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;I didn't lose my linen bedclothes.
I lost my higher quality sleep for a while. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;It's not a big deal to wash the bedclothes first thing in the morning,
but if you forget and do it later in the day,
they might not get dry enough before the night. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/netlify-updating-private-git-submodule/</id><title>Updating a private Git submodule before builds in Netlify</title><link href="https://mtsknn.fi/blog/netlify-updating-private-git-submodule/" /><published>2022-09-15T12:00:00+03:00</published><updated>2022-09-15T12:00:00+03:00</updated><category term="Git"></category><category term="Netlify"></category><content type="html">&lt;p&gt;Automatically updating a private Git submodule before builds is convenient
but requires some setup.&lt;/p&gt;
&lt;h2 id=&quot;why-a-private-git-submodule&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-a-private-git-submodule&quot;&gt;Why a private Git submodule&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mtsknn/mtsknn.fi&quot; class=&quot;link link-external&quot;&gt;My website is open source&lt;/a&gt;,
but the blog posts and other content reside in a separate, private Git repo.&lt;/p&gt;
&lt;p&gt;Tania Rascia explains her rationale for her similar setup in her blog post
&lt;a href=&quot;https://www.taniarascia.com/git-submodules-private-content/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Using Git Submodules for Private Content&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;My website has been open source for as long as it has existed.
Originally, it was a WordPress site,
but only the layout was out there for everyone to see
since the data was saved in a database.
Once I moved to Gatsby,
I kept all the images and posts in a &lt;code&gt;content&lt;/code&gt; directory.
This was way better,
as my content is all conveniently stored in one easy-to-save folder
and the posts are all in beautiful markdown.&lt;/p&gt;
&lt;p&gt;However,
people often like my layout and want to use it,
so they clone and deploy this site.
Sometimes they will just leave up all the posts and images and update the name and image.
Although I subscribe to the &lt;a href=&quot;https://zenhabits.net/uncopyright/&quot; class=&quot;link link-external&quot;&gt;Zenhabits Uncopyright&lt;/a&gt; philosophy towards content –
my content is out there for the world to see and do what they want with it, and it doesn't bother me –
I don't think I should make it &lt;em&gt;quite&lt;/em&gt; so easy to just clone everything I've written in a moment.
If you're going to plagiarize,
you should at least have to do a bit of work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another benefit:
I can store my sloppy drafts and scheduled posts in my private Git repo
so that no one can see them (except me of course).&lt;/p&gt;
&lt;h2 id=&quot;why-automatic-updating&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-automatic-updating&quot;&gt;Why automatic updating&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From the summary of the aforementioned blog post by Tania Rascia:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;My current process for updating the site looks like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make changes to &lt;code&gt;content&lt;/code&gt; repo.&lt;/li&gt;
&lt;li&gt;Commit changes to &lt;code&gt;content&lt;/code&gt; and push to private submodule hosted on GitHub:
&lt;code&gt;git commit &amp;amp;&amp;amp; git push&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pull new updates into local &lt;code&gt;taniarascia.com&lt;/code&gt; repo:
&lt;code&gt;git submodule update --remote&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Commit the new submodule changes and push to public GitHub repo:
&lt;code&gt;git commit &amp;amp;&amp;amp; git push&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Netlify deploys the new site.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's cool,
but &lt;strong&gt;I don't want to update my website repo after modifying my content repo.&lt;/strong&gt;
My process looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Same as above.
(Make changes to &lt;code&gt;content&lt;/code&gt; repo.)&lt;/li&gt;
&lt;li&gt;Same as above.
(Commit changes to &lt;code&gt;content&lt;/code&gt; and push to private submodule hosted on GitHub:
&lt;code&gt;git commit &amp;amp;&amp;amp; git push&lt;/code&gt;.)&lt;/li&gt;
&lt;li&gt;Netlify deploys the new site automatically on the next day
because I have set up
&lt;a href=&quot;/blog/how-to-trigger-daily-netlify-builds-using-github-actions/&quot; class=&quot;link&quot;&gt;automatic daily Netlify builds using GitHub Actions&lt;/a&gt;.
Alternatively I can manually trigger a build on the Netlify dashboard
if I want the content changes to go live immediately (in a few minutes).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are two benefits to this way of working:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I need to work with only one Git repo (the content repo) to write content.&lt;/li&gt;
&lt;li&gt;I can avoid the frequent &amp;quot;update content submodule&amp;quot; commits in my website repo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My website repo points to a commit from 1st Jan 2021 on the content repo,
meaning that I haven't needed an &amp;quot;update content submodule&amp;quot; commit on the website repo
in almost two years.
This is possible because
Netlify automatically updates the private Git submodule (i.e. pulls the latest changes)
before it builds the site.&lt;/p&gt;
&lt;h2 id=&quot;how-to&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-to&quot;&gt;How-to&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First,
&lt;a href=&quot;https://www.taniarascia.com/git-submodules-private-content/&quot; class=&quot;link link-external&quot;&gt;check out the aforementioned blog post by Tania Rascia&lt;/a&gt;.
It's a good primer on the subject.&lt;/p&gt;
&lt;p&gt;When you have a private Git submodule set up,
here are pointers how to make Netlify automatically update it before builds.
These pointers are based on &lt;a href=&quot;https://answers.netlify.com/t/support-guide-using-an-ssh-key-via-environment-variable-during-build/2457&quot; class=&quot;link link-external&quot;&gt;a support guide on Netlify Support Forums&lt;/a&gt;,
but I had to trial and error quite a bit before I got it all working.&lt;/p&gt;
&lt;h3 id=&quot;deploy-key-ssh-key&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#deploy-key-ssh-key&quot;&gt;Deploy key + SSH key&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You need to add &lt;em&gt;two&lt;/em&gt; keys on your private Git repo's settings page on GitHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Netlify deploy key:
this is needed so that Netlify can &lt;em&gt;initially access&lt;/em&gt; the private submodule.
Check the blog post by Tania Rascia for a guide.&lt;/li&gt;
&lt;li&gt;A new SSH public key:
this is needed so that Netlify can &lt;em&gt;update&lt;/em&gt; the private submodule (i.e. pull the latest changes)
before it starts building the site.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent&quot; class=&quot;link link-external&quot;&gt;Generate a new SSH key&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Example on Mac: &lt;code&gt;ssh-keygen -t ed25519 -C &amp;quot;yoursite.com content repo / Netlify&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;-C&lt;/code&gt; flag stands for &amp;quot;comment&amp;quot; –
it's for you so you later know/remember what this SSH key is for&lt;/li&gt;
&lt;li&gt;Save the file e.g. to &lt;code&gt;/Users/you/.ssh/yoursite.com-content-netlify&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Don't set a password or Netlify can't update the submodule&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;public&lt;/strong&gt; key (the shorter one) as a read-only deploy key
on your private repo's settings page on GitHub
&lt;ul&gt;
&lt;li&gt;Name it e.g. &amp;quot;SSH public key (Netlify)&amp;quot;
so you can tell it apart from the other deploy key (&amp;quot;Netlify deploy key&amp;quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;After changing the build image on Netlify
(the previous one I was using was going to be deprecated),
the Netlify deploy key changed too,
so I had to add the new deploy key to the private Git repo's settings on GitHub.
(I'm not 100% sure about this.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;environment-variable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#environment-variable&quot;&gt;Environment variable&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add the &lt;strong&gt;private&lt;/strong&gt; SSH key (the longer one)
to your Netlify site's environment variables.
Before that though you need to modify the key
because environment variables are single-line (not multi-line).&lt;/p&gt;
&lt;p&gt;Your private key looks something like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-text bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;-----BEGIN OPENSSH PRIVATE KEY-----
n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is
...
-----END OPENSSH PRIVATE KEY-----
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the newlines with underscores (e.g. in VS Code or Notepad)
so that it looks like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-text bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;-----BEGIN OPENSSH PRIVATE KEY-----_n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is_..._-----END OPENSSH PRIVATE KEY-----_
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: it doesn't matter whether the private key has a trailing underscore or not.&lt;/p&gt;
&lt;h3 id=&quot;bash-script&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bash-script&quot;&gt;Bash script&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To let Netlify use the SSH key from the environment variables,
create a file called e.g. &lt;code&gt;netlify-setup.sh&lt;/code&gt;
and save it to the website repo's root:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Credit goes to fool and hongaar at&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# https://community.netlify.com/t/support-guide-using-an-ssh-key-via-environment-variable-during-build/2457&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Check if we're running in a Netlify environment&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# See https://www.netlify.com/docs/continuous-deployment/#environment-variables&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; -z &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${DEPLOY_PRIME_URL}&lt;/span&gt;&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 keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Init .ssh dir and expand $SSH_KEY&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; -p ~/.ssh
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${SSH_KEY&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;\\n}&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ~/.ssh/id_rsa
    &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; og-rwx ~/.ssh/id_rsa

    &lt;span class=&quot;token comment&quot;&gt;# Uncomment to debug&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# ls -la ~/.ssh&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# cat ~/.ssh/id_rsa&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# Add host keys&lt;/span&gt;
    ssh-keyscan -H github.com &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; ~/.ssh/known_hosts
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;build-command&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#build-command&quot;&gt;Build command&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Last step!
Modify your build command (e.g. &lt;code&gt;npm run build&lt;/code&gt;)
to first run the Bash script,
then update the private Git submodule,
and then build the site.&lt;/p&gt;
&lt;p&gt;There might be several ways to do this.
I did it by specifying this as my build command in the &lt;code&gt;netlify.toml&lt;/code&gt; file:&lt;/p&gt;
&lt;style&gt;
  /*
    Heh, Tailwind's `table` class
    applied `display: table`
    to one token in the code block below
  */
  .token.table {
    display: inline;
  }
&lt;/style&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-toml bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token key property&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&quot;
    bash ./netlify-setup.sh &amp;amp;&amp;amp;
    GIT_SSH_COMMAND=&quot;ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no&quot; \
      git submodule update --init --remote &amp;amp;&amp;amp;
    npm run build
  &quot;&quot;&quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/mortgage-calculator/</id><title>Mortgage calculations in JS: annuity and fixed principal</title><link href="https://mtsknn.fi/blog/mortgage-calculator/" /><published>2022-09-13T12:00:00+03:00</published><updated>2022-09-13T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Instead of spending 5 minutes to look for and use an existing mortgage calculator,
I wasted time figuring out how to do the calculations from scratch.&lt;/p&gt;
&lt;h2 id=&quot;annuity-vs-fixed-principal&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#annuity-vs-fixed-principal&quot;&gt;Annuity vs fixed principal&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;In annuity the monthly payment is fixed (until the interest rate changes).&lt;/li&gt;
&lt;li&gt;In fixed principal the monthly payment gets smaller after each month;
the first payment is the largest
and larger than in annuity.&lt;/li&gt;
&lt;li&gt;Fixed principal is cheaper over the whole mortgage period (less total interest fees),
but annuity is more affordable in the short term.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I recall reading recently that annuity is used in like 99% of mortgages in Finland.
I can't find that article anymore though,
so I don't know if it's actually 99% or more like 90%.&lt;/p&gt;
&lt;h2 id=&quot;btw-mathjax&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#btw-mathjax&quot;&gt;Btw, MathJax&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Enable &lt;a href=&quot;https://www.mathjax.org/&quot; class=&quot;link link-external&quot;&gt;MathJax&lt;/a&gt; by clicking the button below
for a better reading experience.
It's opt-in because it's a largish download (300+ KB).&lt;/p&gt;
&lt;style&gt;
  /* &lt;kbd&gt; styles */
  #enable-mathjax {
    background-color: #f1f5f9;
    border: 1px solid #97a6ba;
    border-radius: 8px;
    box-shadow: 0 1px 0 0 #97a6ba, inset 0 2px 0 0 #fff;
    display: block;
    margin: 0 auto;
    padding: 4px 8px;
  }
  #enable-mathjax:hover {
    background-color: #fff;
  }
  #enable-mathjax:active {
    background-color: #f1f5f9;
  }
  #enable-mathjax:focus {
    box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
    outline: transparent dotted 2px;
  }

  mjx-container {
    overflow-x: auto;
    padding: 2px 0;
  }
&lt;/style&gt;
&lt;p&gt;&lt;button id=&quot;enable-mathjax&quot;&gt;Load MathJax lib (300+ KB)&lt;/button&gt;&lt;/p&gt;
&lt;script&gt;
;(() =&gt; {
  document.querySelector('#enable-mathjax').addEventListener('click', (e) =&gt; {
    const script = document.createElement('script')
    script.async = true
    script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js'
    document.head.appendChild(script)
    e.target.remove()
  })
})();
&lt;/script&gt;
&lt;p&gt;(It would be nice to run MathJax during the website's build process,
but I'm too lazy to do that now.
I just want to publish this post.)&lt;/p&gt;
&lt;h2 id=&quot;annuity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#annuity&quot;&gt;Annuity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Wikipedia has a clear &lt;a href=&quot;https://en.wikipedia.org/wiki/Amortization_calculator#The_formula&quot; class=&quot;link link-external&quot;&gt;annuity formula&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;$$
A =
\frac{P \times i}
{(1 - (1 + i)^{-n})}
$$&lt;/p&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;\(A\) = monthly payment amount (= monthly principal + monthly interest)&lt;/li&gt;
&lt;li&gt;\(P\) = total loan amount&lt;/li&gt;
&lt;li&gt;\(i\) = monthly interest rate (percentage)&lt;/li&gt;
&lt;li&gt;\(n\) = total number of payments (= number of months)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On that same Wikipedia page,
there's a formula for calculating the remaining loan amount after \(t\) months
(function \(p(t)\)):&lt;/p&gt;
&lt;p&gt;$$
p(t) = Pr^t - A \frac{r^t - 1}{r - 1}
$$&lt;/p&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;p&gt;$$r = 1 + i$$&lt;/p&gt;
&lt;p&gt;It's clearer to use \(1 + i\) in place of \(r\):&lt;/p&gt;
&lt;p&gt;$$
p(t) = P(1 + i)^t - A \frac{(1 + i)^t - 1}{(1 + i) - 1}
$$&lt;/p&gt;
&lt;p&gt;Because now we can simplify \((1 + i) - 1\) to just \(i\):&lt;/p&gt;
&lt;p&gt;$$
p(t) = P(1 + i)^t - A \frac{(1 + i)^t - 1}{i}
$$&lt;/p&gt;
&lt;p&gt;In JavaScript,
with an opening fee and extra monthly fees (not included in the formulas above):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;calculateAnnuity&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  loanAmount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  monthlyFee&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  monthlyInterestPercentage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  months&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  openingFee&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 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; monthlyAnnuity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loanAmount &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; monthlyInterestPercentage&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 number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; monthlyInterestPercentage&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;months&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; monthlyPayment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; monthlyAnnuity &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; monthlyFee
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalPayable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; openingFee &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; monthlyPayment &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; months
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalFees &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; totalPayable &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loanAmount

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; loanAmountLeftAfterOneYear &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    loanAmount &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 number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; monthlyInterestPercentage&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;12&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;
    monthlyAnnuity &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 number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; monthlyInterestPercentage&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;12&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 operator&quot;&gt;/&lt;/span&gt; monthlyInterestPercentage&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;
    monthlyPayment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    totalPayable&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    totalFees&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    loanAmountLeftAfterOneYear&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;fixed-principal&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fixed-principal&quot;&gt;Fixed principal&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The formulas are much simpler
because the monthly principal amount is fixed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;monthly payment amount = monthly principal + interest for the remaining loan amount
&lt;ul&gt;
&lt;li&gt;monthly principal = loan amount / number of months&lt;/li&gt;
&lt;li&gt;interest for the remaining loan amount = remaining loan amount × monthly interest rate&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;loan left after \(t\) months = loan amount - monthly principal × \(t\)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In JavaScript:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;calculateFixedPrincipal&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  loanAmount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  monthlyFee&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  monthlyInterestPercentage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  months&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  openingFee&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 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; monthlyPrincipal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; loanAmount &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; months

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; monthlyPayments &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; months &lt;span class=&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 parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; monthIndex&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; interest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loanAmount &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; monthlyPrincipal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; monthIndex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; monthlyInterestPercentage
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; monthlyPrincipal &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; interest &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; monthlyFee
  &lt;span class=&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; firstMonthPayment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; monthlyPayments&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 keyword&quot;&gt;const&lt;/span&gt; lastMonthPayment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; monthlyPayments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;at&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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&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; array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&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 keyword&quot;&gt;const&lt;/span&gt; totalPayable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; openingFee &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;monthlyPayments&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalFees &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; totalPayable &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; loanAmount
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; loanAmountLeftAfterOneYear &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; loanAmount &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; monthlyPrincipal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&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;
    firstMonthPayment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    lastMonthPayment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    totalPayable&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    totalFees&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    loanAmountLeftAfterOneYear&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example&quot;&gt;Example&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; referenceRate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.482&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// E.g. Euribor 12&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; margin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.55&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; specs &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;loanAmount&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;135_000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;monthlyFee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;monthlyInterestPercentage&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;referenceRate &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; margin&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;12&lt;/span&gt; &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 punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;months&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;openingFee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&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;calculateAnnuity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;specs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; {&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   monthlyPayment:                 576.81,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   totalPayable:               173_192.65,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   totalFees:                   38_192.65,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   loanAmountLeftAfterOneYear: 130_812.64,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// }&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;calculateFixedPrincipal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;specs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; {&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   firstMonthPayment:              681.10,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   lastMonthPayment:               453.26,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   totalPayable:               170_304.30,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   totalFees:                   35_304.30,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   loanAmountLeftAfterOneYear: 129_600.00,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// }&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see,
fixed principal is more expensive in the beginning
but cheaper in the long term (less total fees).
Also, at some point the monthly payments become less than in annuity.&lt;/p&gt;
&lt;h3 id=&quot;thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#thoughts&quot;&gt;Thoughts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At first I though that fixed principal would be better
because it incurs less total fees,
but on the other hand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With my specs (see above) the difference in total fees is only 2,888.35 € &lt;em&gt;over 25 years&lt;/em&gt; –
that's only 115.53 € per year,
or 9.63 € per month.
Not very much.&lt;/li&gt;
&lt;li&gt;Less than ten bucks per month is not a high price to pay
to get consistent monthly payments
and more affordable payments in the beginning.
Especially the second point (more affordable payments in the beginning)
feels more important than slightly smaller total fees over a long period of time
(25 years! I'm hardly that old myself).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's why I wanted to calculate how much of the loan amount would be left after one year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interest rates have recently been increasing rapidly.&lt;/li&gt;
&lt;li&gt;My reference rate is tied to Euribor 12,
i.e. the rate is updated every 12 months.&lt;/li&gt;
&lt;li&gt;I wanted to check how much the monthly payments would be after one year
if the interest rate had raised to 6% (stress test) –
would it matter whether I had been paying the first year with annuity or fixed principal?&lt;/li&gt;
&lt;li&gt;The difference in the remaining loan amount after one year is only 1,212.64 €,
so the effect on the stress test scenario is negligible.
So no, it doesn't really matter which payment type I use in the first year.
&lt;ul&gt;
&lt;li&gt;There &lt;em&gt;is&lt;/em&gt; something I could do to make my life easier in a stress test scenario:
choosing annuity would make the first monthly payments significantly cheaper
(around 250 € in my case).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To help me choose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I should choose fixed principal if I want to:
&lt;ul&gt;
&lt;li&gt;Save less than 3k € in 25 years.
Not a compelling reason.&lt;/li&gt;
&lt;li&gt;Pay less each month after some point.
Not very interesting because that would be in the distant future.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I should choose annuity if I want to:
&lt;ul&gt;
&lt;li&gt;Pay about 100 € less each month (in the beginning).
This sounds good; I could instead invest the money (either in an index fund or in cheese! I like cheese).&lt;/li&gt;
&lt;li&gt;Pay less in a stress test scenario (6% interest rate).
This would increase my peace of mind.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think I might go with annuity.&lt;/p&gt;
&lt;h2 id=&quot;demo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#demo&quot;&gt;Demo&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I started building a calculator for comparing mortgages but lost interest quite quickly,
so here's a half-baked demo:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBmADAOgGwA4A0IAzvAgMYAu8UyIpA9gHYBmEA5hgFaEgGGkBOdWLGQBtNHjQBdAiwTcko0AwCGYRElqMW7Ljy0NKhmgHoTAAgCydfuVYrW8c6RWxSAV1gryN84ApyAB0GM3MAC3JyAAdCJDMwckIAawYGDBYTACNYOlYTMBs7B3gAWhc3T28bEyCg+gZCcmd3fn54BlIAT3MAXnMAcgBRAFUAJT7axgbzbLKnXr6WcYYgkIBBHum6FQZzNTp3QxWLACENjvgVfkIj8wBhDdameFb2p35vJwAKeAx2cwHmhAMr4AIwAJgAlDcACIbMCXVgQZbBCwDDZ0SJtJGscxPeA3ABicMY5FCsC6eJuAHENqp1BN6o0MttEoQNqIguZzCFzOsufzTvz7vyubCRWiuUT+VTOeZRCCUABWAD6aDVeHMYMVGpBGAALDgwRrMIrtfyJJqMGa+scWby+jJZfKlar1ZqzbqDUbzJg9RawW6wVaNTa7ccHXgneCAJzKrCBvUarAYNUWzBurn+4P9ADK5FahDZlAaEaCUn0xDI5AgkxoIJwSBBIAAvnhlGoNOAVEjONwCHUjOQaHUpmUPF5KKsUu4IOQur1PsBZdltqt8gdyJGduZ8oYyR0CfB4FuubvSeSAJKGZ7wBoABWepDa5CKJ53JNChDfGKxDFYh+PIJmwhHoAD5zCXbcR0aM99ynBgZznHpZS5T4VwYNd9kMcwACp3z3S9rwLcgH34J9DCKEDqm3VCQXMYpzE+OiAGp8PPDor0oYjSPIl9HBAnC8OKWDCChZEuWgtj9zvFQOnUbDelg8l4MQrpWKUg8j1lSSfBfWAZI6FQsjmcwfwYbEAPMdSP3JAz5MaPCRO0yZGl01wALZXo3P02SjIQejNlXddDnE5wXMCjDgvIAAZeAmHIVZ4ueAB5Bh4AATQufhkJoiLMI3XDGJYqTCK428SMfZ9KNwvDwXolCSo6FTZy6HCGtQz4mKsxrOJve9Koo-iavMOqGJBKieqI8qeKq-iam3VpyGaHZIJFDS7OfN8uW8gy-MA3LvI8ra8qi2L4sSrjUoyrK32bID5skscKkoAkIAADyoO9+CRUgIEiVwNkXZctkirDN1lDSALfDTeu4ga+P208Py-WUzIso8t2AsCIOcxlGq+n6-oB3p0Py7CLCc0LJPW2T7M83kWlktJBDARdpjaVhSSQKS2VbRjlQ1WCrygeA3pA7pwNW-lJKRMqpm6drGNJqKAvW772iJ2BCqFhgRbF7WbI4qb+rI2b8Vyxblvx9Xfv+rXWNlvrGmsgjNPNrlgNxqYWCuchrD3DaFPx2nn0IcQpC9xovAaf3SUDxpFMN+PCAwbxPmKcb5ok8LCHcMBAcud4OnF8DC6Z1ooHcJ9OpUDUMhL3ZuoyY0xOzvGdt84z0Uxcy-0s1jc9Zmm5NDsTI-MQ6j3pjvDK7hjlbB8eF43M6EqS-grsyy4NmX7CGLVwm7cK8Es-MS3+BWhqfZjj94+O6O-dvkPDGOme9tfug9KOhrd5iuK18umlLe-Bbr3WRJJJgNh4QJxxtuXc8AOjc0+AhMAGRngamAOYKAbBZz0zBOYZsGxgBYwlg1FBaD+AYB8NFOgsw8zq1YGhWhrhjywJFBJZoLxOjHVPCoN6EAwB5wJO8CgNYGDQhwQkbm2DEQJB4TuJEAihEiOrIwCRsiYhYMkSjXKXIGgdAQNzPoHgWhtE6H0Y6wE3yYlNoYJB5DnglwasgvOFDuQjTVBCKhdAaF0PzNiJhswMGK3hPwwRYBhEqFEWo7R3MUDyMgOZcJkToniNieYeJit9GGP6DY3iFiGpWLAUEKAtC87PgwMCKAHQMBIjSvwAAEgAFUsNFDYJg8LNNabhCwAADWUAAeF8XcnzCEIP9X6f4FYgDQAEEAoEGpDNCBcKACzdHmCGfwNZ7D+RLLCrAcZ2xpk4Dmc4aOhBpm8WeOYdwkQ8kqGIOYYE-ARb8GKPwOZoEcyYlIIQAZJhSTbJ2Rs0k+zDkMGmXqU5pBzmXOfNc259zHnPNee8z5zU5z-MBYrLkez6AHP+hCuZipoWwrmVc7KiLHwPPxPM16H0oDmEiDbTWWLQhApFFirZitNkcvYXswQAB3cF0ywSkoeRcuZCB4qfIAHIdjZXyzloKhUirmWK+ZNDti7CioqnFILQhnzoMKwlorPnAL+QC9l+q8VCDVSAFA4rCxwqIp82G5U9XrNxSq419qNWgWSj3bEuIjyeuBQao1JqjnqqdZKkAKLnhovmbHfcIb4CeptT6qNRKQD+tIlJMNwKBW+tNTG+ZTTP6uELTs4t2azXlsrVrPElrsVeojaq0tubY3TITW8j5mqQbs3irsdeI0ABkDAMjjIANznEuBmttta-WfNer7AtVqlW7KzcuzVDyYIfmrfy7dnb-UVr0oe5VhqO3Rq7Q2vSaaW3WsXcem9-qtU7GlY0FQo6QQTqnZEWdWUL0bIBdy9ZvLM3spGHFG8rwz4fGA969llgERIkQwa0CZ6q0bp5aBvlbKVn4fIFUjom6AAkwBmQMFZPqjA8JIifH1ahDkbaRS-w2BIJj-I51XA2CCeROzHiwafCMD4An2Hwn4IiBg4mRRoz7keDjsn+SQ0U70TjrH+R0hMn0ApmmpANyluGtuUwYbGwqrYhGOVjPsM+EJrh8BROUG6pJ6TE06oWBBGqLjJn917npjxtktUxWhRs5JcZ8BflEJ8-yX+ym1qGyhjFpGrt3Um14q+ZLPN4v8nk-+DGMW7qad87sacLUNhPQnPADFHRPgRd+a3GzYU8YsAZQTDWR9eiVY+PSz6LK7Z1Z+aJU+Nnz47A6eYLpbScJ9KyxB4rR7DUwoldMz9nyKPaebOh8NQzVkUcgfwaBdHGAIKYUFMGGCtEaO5mgAhEItsAtWVl71e3gCBYe+QJ7C3lWvYO0dvJz47MwYc05+A92sVfaa0e37UDvAYAB4YT4rmkTg8e5umzu3QL7dh+QeH8MgdPBBx8FzqGGCo8++j4zmPseHbh-A2reWoYQSu7gm7d2PuQ6h1uxly3nVzN7UmrHwA-t05O7V1TYOOdrOeyCmHtPcf08+NsBCLVjuu3juTznXPZdC5FwrsXSuytzm8XpXaxlNeU52xTmnR3FfK9Uib9yU8Lcy922clb-ObCov7Zb4zNvRdpVq-b1Xv9V4XRSkArK93Xdo5G1z6nwucdq9O61vrh9XBpAgL7FNGupeu+t4n+Xyfaup6gO122GeH45+fuQF333ue66T4r0v5fNaO58rPBAdftcvcb0X5v7008dYz5PW83ee+Y5l1yf3+vA+fBb-1yvIMyZ-3OuvTeUeis95AxTubeGYv9M01v4FjWdmcDoEiT4uno+5SxSRoFWK9prMPy2NsIBtM0HMk+DAvy+wGEHDQEgIIJ-GwvRMUL2tzKwEXNOrKJAoYMUEwGoBAOSNzLuHQIck+DAduHAeQMUIQBAAAF7wDczRhoAACkWBRWQQwy-kUsEBI0kQb05ghAQg0A5gAAbpcOnOAV7o4lgVyALp+sUIKtAFzJqIwfwU8rwW8j4JEMIaIaENzGCBIcUnuKAcyKQIkFAVhFAKUEIDYNzAAMRHjwCSHsHPDVhlDFCuBsAMDczAgRB0BgCUHzSkgaifbqHSE8GOFgDcwgiMHMGsGMqcH8DcG9oQiSEC7fSsDhB+EBEsGwBsEhFhHSERGyj-QwDYg3ZWitDOGyiUBvS4E2GsB2FnxsDhAuHIieCgGJFpTFDLLlHkB+EYBaiSHI6lFoCSEZHYJ-jFCfp+G5GVFBA-7wrZSYIFFFGJElHcwUrToELDGfr8jjGiyTG2HcyfpzEezzSVJeFjFSEvKJrRHhDyFQBiHKFvRzFUGpBUpkQ0rM4THFD5jbCEB-bcw3EuDECXEtgyDv4dg0DoTOCuDjiVD8AthAA&quot; class=&quot;link link-external&quot;&gt;Mortgage calculator on flems.io&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-read-only-array-sort/</id><title>Sorting a read-only array is OK if it has only 1 or 0 items</title><link href="https://mtsknn.fi/blog/js-read-only-array-sort/" /><published>2022-09-01T12:00:00+03:00</published><updated>2022-09-01T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;Huh.
But if the array has 2+ items,
attempting to sort it will cause a TypeError.&lt;/p&gt;
&lt;h2 id=&quot;example-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-1&quot;&gt;Example 1&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&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 function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&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;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'b'&lt;/span&gt;&lt;span class=&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;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// TypeError&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Errors in different browsers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chrome / Edge: &amp;quot;TypeError: Cannot assign to read only property '0' of object '[object Array]'&amp;quot;&lt;/li&gt;
&lt;li&gt;Firefox: &amp;quot;TypeError: 0 is read-only&amp;quot;&lt;/li&gt;
&lt;li&gt;Safari: &amp;quot;TypeError: Attempted to assign to readonly property.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;example-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-2&quot;&gt;Example 2&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; arr &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;
arr&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 operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'b'&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// TypeError&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The errors are slightly different:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chrome / Edge: &amp;quot;TypeError: Cannot add property 0, object is not extensible&amp;quot;&lt;/li&gt;
&lt;li&gt;Firefox: &amp;quot;TypeError: can't define property 0: Array is not extensible&amp;quot;&lt;/li&gt;
&lt;li&gt;Safari: same as in Example 1&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pondering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pondering&quot;&gt;Pondering&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I use mainly Firefox.
Its error message &amp;quot;0 is read-only&amp;quot; is not very enlightening,
so when investigating a related bug,
I didn't grasp at first that the problem was about a read-only array.
Meh.&lt;/p&gt;
&lt;p&gt;If an array is empty or has only one item,
sorting the array won't modify the array
because there are not enough items to move around.
So no error even if the array is read-only.
Makes sense but was surprising (hence this blog post).&lt;/p&gt;
&lt;p&gt;On the other hand:
if a read-only array has 2+ items and is already sorted,
trying to sort it causes a TypeError,
even though the array is already sorted!
Makes sense but is also mildly confusing –
why is the array being modified if it's already sorted?&lt;/p&gt;
&lt;p&gt;If a read-only array has only &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays&quot; class=&quot;link link-external&quot;&gt;empty slots&lt;/a&gt;,
sorting it is OK,
which is weird:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token comment&quot;&gt;//=&gt; 3&lt;/span&gt;
arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK but weird&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;fix-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fix-1&quot;&gt;Fix 1&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort&quot; class=&quot;link link-external&quot;&gt;The &lt;code&gt;sort() method&lt;/code&gt;&lt;/a&gt;
sorts an array in-place,
i.e. sorting an array modifies it.&lt;/p&gt;
&lt;p&gt;You might want to
first &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice&quot; class=&quot;link link-external&quot;&gt;copy the array with &lt;code&gt;slice()&lt;/code&gt;&lt;/a&gt;
and then sort the copied array:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'b'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// TypeError&lt;/span&gt;
arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;fix-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fix-2&quot;&gt;Fix 2&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TypeScript would have spotted the error for me right away:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'b'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//  ^? Property 'sort' does not exist on type 'readonly string[]'.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the other hand,
the TypeScript compiler doesn't seem to know that sorting a read-only array is OK
if the array has only 1 or 0 items:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//  ^? Property 'sort' does not exist on type 'readonly string[]'.&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 👆 Compile-time error but no runtime error, so 🤷‍♂️&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ha! 😄&lt;/p&gt;
&lt;p&gt;On a serious note:
I think it's better that the TypeScript compiler always disallows sorting read-only arrays.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/tongue-position/</id><title>Correct tongue position in 3 steps</title><link href="https://mtsknn.fi/blog/tongue-position/" /><published>2022-08-16T12:00:00+03:00</published><updated>2022-08-16T12:00:00+03:00</updated><category term="Breathing"></category><category term="Health"></category><category term="Running"></category><content type="html">&lt;p&gt;Say &amp;quot;n&amp;quot; and cluck and relax. Easy!
Correct tongue position makes nasal breathing easier.&lt;/p&gt;
&lt;h2 id=&quot;step-1-find-the-right-spot-for-the-tip-of-the-tongue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-1-find-the-right-spot-for-the-tip-of-the-tongue&quot;&gt;Step 1: Find the right spot for the tip of the tongue&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The right spot is in the roof of the mouth,
behind the upper front teeth.&lt;/p&gt;
&lt;p&gt;Saying the letter &amp;quot;n&amp;quot; aloud will guide the tip of the tongue to the right spot.&lt;/p&gt;
&lt;h2 id=&quot;step-2-place-the-rest-of-the-tongue-against-the-roof-of-the-mouth&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-2-place-the-rest-of-the-tongue-against-the-roof-of-the-mouth&quot;&gt;Step 2: Place the rest of the tongue against the roof of the mouth&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Placing the whole tongue to the roof of the mouth
will pull down the roof of the mouth (i.e. the hard palate).
The roof of the mouth is also the floor of the nose,
so this helps increase the nasal space,
making breathing through the nose easier.&lt;/p&gt;
&lt;p&gt;One way to guide the whole tongue to the roof of the mouth
is to cluck with your tongue.
(Check the video link below for an example.)&lt;/p&gt;
&lt;h2 id=&quot;step-3-relax&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-3-relax&quot;&gt;Step 3: Relax&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Keep your lips together &lt;em&gt;gently&lt;/em&gt;.
Relax the whole head as well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Relax the tongue&lt;/li&gt;
&lt;li&gt;Relax the lips&lt;/li&gt;
&lt;li&gt;Relax the jaws&lt;/li&gt;
&lt;li&gt;Relax the eyes&lt;/li&gt;
&lt;li&gt;Relax the face&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;bonus-relax-the-diaphragm&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-relax-the-diaphragm&quot;&gt;Bonus: Relax the diaphragm&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Keep the diaphragm relaxed as well
and practice &lt;a href=&quot;https://en.wikipedia.org/wiki/Diaphragmatic_breathing&quot; class=&quot;link link-external&quot;&gt;diaphragmatic breathing&lt;/a&gt;
at all times.&lt;/p&gt;
&lt;h2 id=&quot;video-guide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#video-guide&quot;&gt;Video guide&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The three steps are from
&lt;a href=&quot;https://www.youtube.com/watch?v=MBPBthM1lcw&quot; class=&quot;link link-external&quot;&gt;a YouTube video called &lt;em&gt;STOP Mouth Breathing – Try This&lt;/em&gt;&lt;/a&gt;
that I accidentally found when looking for something else.
(I slightly expanded the 3rd step above and added the bonus step.)&lt;/p&gt;
&lt;p&gt;The video starts by explaining some benefits of nasal breathing.
&lt;a href=&quot;https://www.youtube.com/watch?v=MBPBthM1lcw&amp;amp;t=102s&quot; class=&quot;link link-external&quot;&gt;The 3-step instructions start at 1:42 of the video.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;why&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why&quot;&gt;Why?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Nasal breathing (i.e. breathing in and out through the nose) at all times
is essential for your health.
&amp;quot;At all times&amp;quot; includes breathing while sleeping and during exercise!&lt;/p&gt;
&lt;p&gt;If you are into running,
try running with the mouth closed.
It will be hard at first,
but try it for a month.
I'm sure you'll like it so much more
that you'll never want to run with an open mouth anymore.&lt;/p&gt;
&lt;h2 id=&quot;the-2nd-step-is-important&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-2nd-step-is-important&quot;&gt;The 2nd step is important&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I'm calling it out because
I have been practicing nasal breathing for several years,
but I didn't know that the whole tongue should be against the roof of the mouth.
Whoops. 🙉
I just recently learned it from the video.&lt;/p&gt;
&lt;p&gt;Now nasal breathing without the 2nd step –
i.e. with the tip of the tongue at the roof of the mouth
but the rest of the tongue hanging at the floor of the mouth –
feels somewhat weird.
Probably because without the step the nasal space is reduced.&lt;/p&gt;
&lt;p&gt;Don't make the mistake that I was doing for several years. 🤙&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/running-vs-jogging/</id><title>Running vs jogging</title><link href="https://mtsknn.fi/blog/running-vs-jogging/" /><published>2022-08-15T12:00:00+03:00</published><updated>2022-08-15T12:00:00+03:00</updated><category term="English"></category><category term="Running"></category><content type="html">&lt;p&gt;Jogging is one type of running.
When I run, I mostly jog,
but I still think I'm a runner, not a jogger.
Huh?&lt;/p&gt;
&lt;p&gt;Here's &lt;a href=&quot;https://www.dictionary.com/browse/jog&quot; class=&quot;link link-external&quot;&gt;one definition for jogging on Dictionary.com&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;to run at a leisurely, slow pace, especially as an outdoor exercise&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, jogging is slow running.&lt;/p&gt;
&lt;p&gt;Jogging is running,
but not all running is jogging.
For example,
sprinting is also running
(but sprinting is not jogging).&lt;/p&gt;
&lt;p&gt;What is &amp;quot;slow running&amp;quot; is personal.
If you are running and feel that you could easily run faster,
maybe your current pace is a jogging pace (i.e. a slow pace).&lt;/p&gt;
&lt;p&gt;It doesn't matter much which word you use.
Though sometimes the distinction can be useful
as &lt;a href=&quot;https://old.reddit.com/r/running/comments/ns8r3d/do_you_feel_theres_a_difference_between_jogging/h0kzgf5/&quot; class=&quot;link link-external&quot;&gt;someone writes on Reddit&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I feel like they're interchangeable for the most part.&lt;/p&gt;
&lt;p&gt;But like,
if I'm talking to a non-runner about my workouts for some reason,
I might say something like
&amp;quot;I'll run fast for a mile,
then jog for a half mile,
and repeat that six times&amp;quot;
just because I feel like they'll get that &amp;quot;jog&amp;quot; means &amp;quot;run slower&amp;quot; in that instance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;quot;Running&amp;quot; also sounds cooler than &amp;quot;jogging,&amp;quot;
so I consider myself a runner,
even though I almost always aim for easy runs.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/pocket-phone/</id><title>Stop keeping your phone in your pocket</title><link href="https://mtsknn.fi/blog/pocket-phone/" /><published>2022-08-04T12:00:00+03:00</published><updated>2022-08-04T12:00:00+03:00</updated><category term="NoSurf"></category><content type="html">&lt;p&gt;A trouser pocket is way too easily reachable.
I often find myself reaching for my phone automatically
even if I don't have anything to do with the phone.&lt;/p&gt;
&lt;h2 id=&quot;discipline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#discipline&quot;&gt;Discipline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Maybe you can reduce your phone usage with discipline,
but then it doesn't make sense to keep your phone one hand gesture away.
It won't be just about discipline anymore;
it will also be about addiction and automatic habits.&lt;/p&gt;
&lt;h2 id=&quot;addiction&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#addiction&quot;&gt;Addiction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Addiction is easily more powerful than discipline.
Especially if you need to be disciplined all the time,
like if you have your phone always easily reachable (in your pocket).
Trying to be disciplined all the time wastes mental energy.&lt;/p&gt;
&lt;p&gt;It doesn't make sense for a drug addict to keep drugs in their pocket.&lt;/p&gt;
&lt;p&gt;If you are addicted to your phone –
and I think most people are –
you are a junkie and your phone is your drug.&lt;/p&gt;
&lt;h2 id=&quot;automatic-habits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#automatic-habits&quot;&gt;Automatic habits&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Taking a phone from your pocket is just one step:
put your hand in your pocket and grab the phone.
It's easy to do that automatically,
without even thinking about that.&lt;/p&gt;
&lt;p&gt;Trying to avoid automatic habits wastes mental energy too.
Instead, make the habit impossible –
keep your phone away from your pocket.&lt;/p&gt;
&lt;p&gt;If you are at home,
keep your phone out of sight,
like in a closet behind doors
(but not in your bedroom!).&lt;/p&gt;
&lt;p&gt;If you are elsewhere,
keep your phone in a back bag.
Taking your phone now requires more than one step:
first you have to take the bag from your back,
than open a zipper,
and &lt;em&gt;then&lt;/em&gt; can you grab the phone.
Doing these steps probably isn't very automatic.&lt;/p&gt;
&lt;p&gt;A fanny pack would be cool too,
though I wonder if taking a phone from one would quickly become too easy and automatic.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/toggleable-react-state/</id><title>Toggleable React state with a 1-line `useReducer`</title><link href="https://mtsknn.fi/blog/toggleable-react-state/" /><published>2022-06-05T12:00:00+03:00</published><updated>2022-06-05T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;Say goodbye to &lt;code&gt;useState&lt;/code&gt;
and a silly toggler function calling the state setter.
Be cool and use a tiny reducer instead.&lt;/p&gt;
&lt;h2 id=&quot;example-enabled-state&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-enabled-state&quot;&gt;Example: &amp;quot;enabled&amp;quot; state&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;typical-solution-with-usestate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#typical-solution-with-usestate&quot;&gt;Typical solution with &lt;code&gt;useState&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;enabled&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setEnabled&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&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 function-variable function&quot;&gt;toggleEnabled&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setEnabled&lt;/span&gt;&lt;span class=&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;previous&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 operator&quot;&gt;!&lt;/span&gt;previous&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;toggleEnabled&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;Toggle&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2 lines – so long and verbose!&lt;/p&gt;
&lt;h3 id=&quot;cool-solution-with-usereducer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cool-solution-with-usereducer&quot;&gt;Cool solution with &lt;code&gt;useReducer&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#usereducer&quot; class=&quot;link link-external&quot;&gt;React's &lt;code&gt;useReducer&lt;/code&gt; hook&lt;/a&gt;
takes a reducer function and an initial value:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;enabled&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toggleEnabled&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useReducer&lt;/span&gt;&lt;span class=&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;previous&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 operator&quot;&gt;!&lt;/span&gt;previous&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;toggleEnabled&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;Toggle&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only 1 line.
So cool! 😎&lt;/p&gt;
&lt;p&gt;This is a bit cryptic at first,
and maybe I wouldn't use it in any &amp;quot;real&amp;quot; code,
but I found this intriguing and wanted to share it.&lt;/p&gt;
&lt;p&gt;I picked this from
&lt;a href=&quot;https://tkdodo.eu/blog/things-to-know-about-use-state&quot; class=&quot;link link-external&quot;&gt;TkDodo's blog post &lt;em&gt;Things to know about useState&lt;/em&gt;&lt;/a&gt;
(from the &amp;quot;Bonus 2&amp;quot; section).&lt;/p&gt;
&lt;h2 id=&quot;another-example-toggling-a-numeric-value&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#another-example-toggling-a-numeric-value&quot;&gt;Another example: toggling a numeric value&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Toggling between 250 and 750:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;duration&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toggleDuration&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useReducer&lt;/span&gt;&lt;span class=&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;previous&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;previous &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&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;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;250&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;toggleDuration&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;Toggle&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whoops, 4 lines. 🥲
But I invented this myself! 😄&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/auto-animate/</id><title>1 line of code to animate element additions, removals and moves</title><link href="https://mtsknn.fi/blog/auto-animate/" /><published>2022-05-28T12:00:00+03:00</published><updated>2022-05-28T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mithril.js"></category><category term="React"></category><content type="html">&lt;p&gt;AutoAnimate is a JS library that provides simple animations with no effort.
Works with Mithril.js, React and any other JS app.&lt;/p&gt;
&lt;h2 id=&quot;highlights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#highlights&quot;&gt;Highlights&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://auto-animate.formkit.com/&quot; class=&quot;link link-external&quot;&gt;AutoAnimate&lt;/a&gt; is a &amp;quot;zero-config, drop-in animation utility&amp;quot;&lt;/li&gt;
&lt;li&gt;Improves UX very much
&lt;ul&gt;
&lt;li&gt;Animated element modifications are easier to spot&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Very easy to use: just a single function (or React hook)
&lt;ul&gt;
&lt;li&gt;Great for business apps when you can't spend time on fancy stuff like animations
(but great for other apps as well)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Very lightweight
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bundlephobia.com/package/@formkit/auto-animate@1.0.0-beta.1&quot; class=&quot;link link-external&quot;&gt;BundlePhopia reports AutoAnimate's minzipped size to be only 2.2 KB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;reactjs-example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#reactjs-example&quot;&gt;React.js example&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From &lt;a href=&quot;https://auto-animate.formkit.com/&quot; class=&quot;link link-external&quot;&gt;AutoAnimate's website&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useAutoAnimate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'@formkit/auto-animate/react'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyList&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;animationParent&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useAutoAnimate&lt;/span&gt;&lt;span class=&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;animationParent&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* 🪄 Magic animations for your list */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the import statement is not counted,
that's only two lines of code.
Nice!&lt;/p&gt;
&lt;p&gt;(The &lt;a href=&quot;#mithriljs-example&quot; class=&quot;link link-anchor&quot;&gt;Mithril.js example&lt;/a&gt; below works with only one line of code.)&lt;/p&gt;
&lt;h3 id=&quot;empty-lessulgreater-is-problematic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#empty-lessulgreater-is-problematic&quot;&gt;Empty &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; is problematic&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you don't want to render an empty &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; element,
you need to use AutoAnimate on the &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;'s parent element too:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useAutoAnimate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'@formkit/auto-animate/react'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token 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;parent&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useAutoAnimate&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useAutoAnimate&lt;/span&gt;&lt;span class=&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 punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;parent&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&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;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* Render items */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;But there's currently an open React-specific GitHub issue that
&lt;a href=&quot;https://github.com/formkit/auto-animate/issues/8&quot; class=&quot;link link-external&quot;&gt;AutoAnimate doesn't work with containers that are not initially rendered&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;manual-exit-animations-would-be-difficult&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#manual-exit-animations-would-be-difficult&quot;&gt;Manual exit animations would be difficult&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Animating the removal of an element is tricky in React
because when React removes an element from the DOM,
the element is removed immediately.
There's no time to run CSS animations.&lt;/p&gt;
&lt;p&gt;If I interpreted &lt;a href=&quot;https://github.com/formkit/auto-animate&quot; class=&quot;link link-external&quot;&gt;AutoAnimate's source code&lt;/a&gt; correctly,
it animates element removal like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;React (or whatever you're using) removes an element from the DOM.&lt;/li&gt;
&lt;li&gt;AutoAnimate adds the element back to the DOM!&lt;/li&gt;
&lt;li&gt;AutoAnimate triggers an animation for the element.&lt;/li&gt;
&lt;li&gt;AutoAnimate removes the element from the DOM
after the animation is finished.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sounds a bit hacky and risky to modify a React-rendered DOM like this,
but seems to work fine.
Quite clever actually!&lt;/p&gt;
&lt;h2 id=&quot;mithriljs-example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#mithriljs-example&quot;&gt;Mithril.js example&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://mithril.js.org/&quot; class=&quot;link link-external&quot;&gt;Mithril.js&lt;/a&gt; is so cool that you only need one line of code:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; autoAnimate &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'@formkit/auto-animate'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyList&lt;/span&gt;&lt;span class=&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;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;view&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;=&gt;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul'&lt;/span&gt;&lt;span class=&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-variable function&quot;&gt;oncreate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;vnode&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 function&quot;&gt;autoAnimate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vnode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dom&lt;span class=&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;// Render items&lt;/span&gt;
      &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://mithril.js.org/lifecycle-methods.html#oncreate&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;oncreate&lt;/code&gt; lifecycle hook in Mithril.js&lt;/a&gt;
is like the good old &lt;a href=&quot;https://reactjs.org/docs/react-component.html#componentdidmount&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;componentDidMount&lt;/code&gt; lifecycle method in React&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vnode.dom&lt;/code&gt; points to the DOM element, so it's like a ref in React.&lt;/p&gt;
&lt;p&gt;In Mithril.js,
components &lt;em&gt;and&lt;/em&gt; virtual DOM nodes have lifecycle hooks
and &amp;quot;automatic&amp;quot; refs (no need for something like &lt;code&gt;createRef&lt;/code&gt; or &lt;code&gt;useRef&lt;/code&gt;).
Super useful.&lt;/p&gt;
&lt;h3 id=&quot;empty-lessulgreater-is-no-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#empty-lessulgreater-is-no-problem&quot;&gt;Empty &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; is no problem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Like with React,
you'll still need to use AutoAnimate on the &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;'s parent element too
if you don't want to render an empty &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; autoAnimate &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'@formkit/auto-animate'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyList&lt;/span&gt;&lt;span class=&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;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;attrs&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; items &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 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 function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'div'&lt;/span&gt;&lt;span class=&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-variable function&quot;&gt;oncreate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;vnode&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 function&quot;&gt;autoAnimate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vnode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dom&lt;span class=&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;
        items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul'&lt;/span&gt;&lt;span class=&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-variable function&quot;&gt;oncreate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;vnode&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 function&quot;&gt;autoAnimate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vnode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dom&lt;span class=&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;// Render items&lt;/span&gt;
          &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the aforementioned React-specific issue is not a problem with Mithril.js,
things just work.
Did I say that Mithril.js is cool!&lt;/p&gt;
&lt;h3 id=&quot;manual-exit-animations-would-be-easy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#manual-exit-animations-would-be-easy&quot;&gt;Manual exit animations would be... easy!&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://mithril.js.org/lifecycle-methods.html#onbeforeremove&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;onbeforeremove&lt;/code&gt; lifecycle hook in Mithril.js&lt;/a&gt;
makes implementing exit animations easy.
From the docs (code example slightly edited by me):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;onbeforeremove(vnode)&lt;/code&gt; hook is called before a DOM element is detached from the document.
If a Promise is returned,
Mithril.js only detaches the DOM element after the promise completes.
[...]&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Fader &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 function&quot;&gt;onbeforeremove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;vnode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    vnode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dom&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'fade-out'&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 keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&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-variable function&quot;&gt;view&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'div'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Bye'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;AutoAnimate still has its place though –
it's great for adding quick and easy animations with no effort.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/button-type-button/</id><title>Your Button component should default to `type=&quot;button&quot;`</title><link href="https://mtsknn.fi/blog/button-type-button/" /><published>2022-05-27T12:00:00+03:00</published><updated>2022-05-27T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;A &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element defaults to &lt;code&gt;type=&amp;quot;submit&amp;quot;&lt;/code&gt;
which can cause accidental form submissions.
Make &lt;code&gt;type=&amp;quot;button&amp;quot;&lt;/code&gt; the default in your Button component
to make your life easier.&lt;/p&gt;
&lt;h2 id=&quot;typebutton-vs-typesubmit&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#typebutton-vs-typesubmit&quot;&gt;&lt;code&gt;type=&amp;quot;button&amp;quot;&lt;/code&gt; vs &lt;code&gt;type=&amp;quot;submit&amp;quot;&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element without a &lt;code&gt;type&lt;/code&gt; attribute
defaults to &lt;code&gt;type=&amp;quot;submit&amp;quot;&lt;/code&gt;.
Clicking a submit button associated with a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;
submits the form
unless &lt;code&gt;event.preventDefault()&lt;/code&gt; is called.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element with &lt;code&gt;type=&amp;quot;button&amp;quot;&lt;/code&gt; on the other hand
does nothing by default when clicked.
Calling &lt;code&gt;event.preventDefault()&lt;/code&gt; does nothing
because there's no default action to prevent.&lt;/p&gt;
&lt;p&gt;Setting your Button component to default to &lt;code&gt;type=&amp;quot;button&amp;quot;&lt;/code&gt;
allows you to not worry about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;accidental form submissions&lt;/li&gt;
&lt;li&gt;having to remember call &lt;code&gt;event.preventDefault()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, using &lt;code&gt;&amp;lt;Button type=&amp;quot;submit&amp;quot;&amp;gt;&lt;/code&gt; makes it explicit that it's a submit button.&lt;/p&gt;
&lt;h2 id=&quot;example-with-react-and-typescript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-with-react-and-typescript&quot;&gt;Example with React and TypeScript&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-tsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ButtonHTMLAttributes&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLButtonElement&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'submit'&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 function-variable function&quot;&gt;Button&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; children&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Props&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token spread&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'button'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Usage:&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;&lt;span class=&quot;token class-name&quot;&gt;Button&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 comment&quot;&gt;// Defaults to `type=&quot;button&quot;`&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;&lt;span class=&quot;token class-name&quot;&gt;Button&lt;/span&gt;&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;submit&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; prop's value in &lt;code&gt;React.ButtonHTMLAttributes&amp;lt;HTMLButtonElement&amp;gt;&lt;/code&gt;
is &lt;code&gt;&amp;quot;submit&amp;quot; | &amp;quot;button&amp;quot; | &amp;quot;reset&amp;quot; | undefined&lt;/code&gt;.
I'm restricting the value to &lt;code&gt;&amp;quot;submit&amp;quot; | undefined&lt;/code&gt;,
so that only &lt;code&gt;type=&amp;quot;submit&amp;quot;&lt;/code&gt; is allowed.
(Omitting the prop is also allowed.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;type=&amp;quot;button&amp;quot;&lt;/code&gt; is not allowed
because it's the default,
so it would be unnecessary noise.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type=&amp;quot;reset&amp;quot;&lt;/code&gt; is not allowed
because reset buttons (i.e. buttons that empty the whole form) are so stupid. 🤡
Not on my watch!&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/illegal-invocations-in-ts/</id><title>Preventing &quot;illegal invocation&quot; errors in TypeScript</title><link href="https://mtsknn.fi/blog/illegal-invocations-in-ts/" /><published>2022-04-17T12:00:00+03:00</published><updated>2022-04-17T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;The TypeScript compiler could help prevent &amp;quot;illegal invocation&amp;quot; errors at compile time,
at least theoretically.&lt;/p&gt;
&lt;h2 id=&quot;illegal-invocation-errors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#illegal-invocation-errors&quot;&gt;Illegal invocation errors?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Chromium browsers throw an &amp;quot;illegal invocation&amp;quot; error when
&lt;strong&gt;calling a function whose &lt;code&gt;this&lt;/code&gt; keyword isn't referring to the object where it originally did&lt;/strong&gt;,
i.e. when the &amp;quot;context&amp;quot; of the function is lost.&lt;/p&gt;
&lt;p&gt;Other browsers and Node.js produce different error messages.&lt;/p&gt;
&lt;p&gt;Check out my earlier blog post for more details:
&lt;a href=&quot;/blog/illegal-invocations-in-js/&quot; class=&quot;link&quot;&gt;&amp;quot;Illegal invocation&amp;quot; errors in JavaScript&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;typescript-is-of-no-help-by-default&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#typescript-is-of-no-help-by-default&quot;&gt;TypeScript is of no help by default&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default,
TypeScript doesn't balk at this code,
resulting in runtime errors when calling the functions:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abortController &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;AbortController&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; abort &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; abortController

&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelector
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelectorAll

&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'#foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;declaring-the-type-of-this&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#declaring-the-type-of-this&quot;&gt;Declaring the type of &lt;code&gt;this&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TypeScript &lt;em&gt;could&lt;/em&gt; spot the errors at compile time
because you can &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/functions.html#declaring-this-in-a-function&quot; class=&quot;link link-external&quot;&gt;declare the type of a function's &lt;code&gt;this&lt;/code&gt; keyword in TypeScript&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example,
the default &lt;code&gt;Document&lt;/code&gt; interface specifies the &lt;code&gt;querySelector&lt;/code&gt; method like this:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; HTMLElementTagNameMap&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    selectors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&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; HTMLElementTagNameMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&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;null&lt;/span&gt;
  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; SVGElementTagNameMap&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    selectors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&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; SVGElementTagNameMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&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;null&lt;/span&gt;
  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;E&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Element&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    selectors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;E&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// + many other methods and properties&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(The &lt;code&gt;querySelector&lt;/code&gt; method is specified three times on purpose;
this is called &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads&quot; class=&quot;link link-external&quot;&gt;function overloading&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;If the interface also specified the type of the &lt;code&gt;querySelector&lt;/code&gt; method's &lt;code&gt;this&lt;/code&gt; keyword,
the TypeScript compiler wouldn't let you call the method illegally:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; HTMLElementTagNameMap&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Document&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    selectors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&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; HTMLElementTagNameMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&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;null&lt;/span&gt;
  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; SVGElementTagNameMap&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Document&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    selectors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&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; SVGElementTagNameMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&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;null&lt;/span&gt;
  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;E&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Element&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Document&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    selectors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;E&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelector
&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Compile-time error&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// This method hasn't been patched:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelectorAll
&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK at compile time but results in a runtime error&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The compile-time error would be something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The 'this' context of type 'void' is not assignable to method's 'this' of type 'Document'.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgCIHsEFcC2FzIDeAUMsgI5bQCeAyhADYQJjpQA8A0shAB6QgAJgGdkAawjV0MZAAkAKgFkAMgFEmecPLgBzAHJw8iuAAcAfAApSZZGAAWwYQC40mXPjAAaa2WGNmrFDOyJzWAJQuCirqEJpg2vqGEMYmANqcALrIAD7IIFgMDNaUNPRMLGxcPPz4IuKS0si0AGoA4jFxCQZGppY+tg7BGNhx3jbIfuWBwaFkEU1tHR5dSSnpWbn5hcVUUHT+FRyq1QJ1SwQAvMjnYH3j9o4uw+7gYzaTAWzBwmBQoDrhFzHTYFIoAX2IxAA9FDkAB5ThOYiCNxxAB0JT2ZU+UAsAHI0TB0Og8WFITDkABhdA4EzAJgAWjAwDwPCgUDYSIQ6BAP2QABJkFcUSMPBjdvspmxiPz8YTiaTybD5INkHh7OhBMg7HBhCA8WBkAAjCD4ZAmOBgBB2CCCbwU4ToZDAMB40QI5CW5Dc2n0lDMvDQ2FGrCGqAQYQFMCiUCe5BQLDgFkoaAcqBcnl8-mC4WosWYyU4gCC22zcqJJLJQA&quot; class=&quot;link link-external&quot;&gt;Demo on TS Playground&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;declaration-merging&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#declaration-merging&quot;&gt;Declaration merging&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You could actually copy that partial interface (with only the patched &lt;code&gt;querySelector&lt;/code&gt; methods) to your codebase.
It would be merged with the default &lt;code&gt;Document&lt;/code&gt; interface
because of &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/declaration-merging.html&quot; class=&quot;link link-external&quot;&gt;declaration merging&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, to get comprehensive compile-time safety against &amp;quot;illegal invocation&amp;quot; errors,
you would need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Specify the type of the &lt;code&gt;this&lt;/code&gt; keyword for &lt;em&gt;all&lt;/em&gt; applicable methods of the &lt;code&gt;Document&lt;/code&gt; interface.&lt;/li&gt;
&lt;li&gt;Do the same for other interfaces as well, e.g. the &lt;code&gt;AbortController&lt;/code&gt; interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This doesn't feel like it belongs to application code.&lt;/p&gt;
&lt;p&gt;Ideally the interfaces would be fixed in TypeScript.
Or maybe there could be a library that exports patched interfaces
that you could import once in your own code.&lt;/p&gt;
&lt;p&gt;Note that in your own methods you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Declare strict types for the &lt;code&gt;this&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;Use better error messages than &amp;quot;illegal invocation.&amp;quot;&lt;/li&gt;
&lt;li&gt;Avoid the &lt;code&gt;this&lt;/code&gt; parameter altogether.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/react-links-in-html/</id><title>Client-side navigation and React's `dangerouslySetInnerHTML`</title><link href="https://mtsknn.fi/blog/react-links-in-html/" /><published>2022-04-03T12:00:00+03:00</published><updated>2022-04-05T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;To handle internal link clicks when using &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;,
attach click event listeners to the rendered links.
In the listener, push the link to the browser history.&lt;/p&gt;
&lt;h2 id=&quot;overview&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#overview&quot;&gt;Overview&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Render the HTML with &lt;a href=&quot;https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;&lt;/a&gt;.
Remember to use only safe HTML!&lt;/li&gt;
&lt;li&gt;When the component mounts,
attach click event listeners to the links.
In the event listener,
push the link to the browser history if it's an internal link.&lt;/li&gt;
&lt;li&gt;When the component unmounts,
remove the click event listeners to avoid memory leaks.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;sample-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sample-code&quot;&gt;Sample code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using TypeScript:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-tsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; RefObject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useEffect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useRef &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react'&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; useNavigate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react-router-dom'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;HtmlContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; html &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; html&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLDivElement&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useLinkClickHandlers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ref&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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;__html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; html &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 class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useLinkClickHandlers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ref&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RefObject&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLDivElement&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 keyword&quot;&gt;const&lt;/span&gt; navigate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useNavigate&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&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 keyword&quot;&gt;const&lt;/span&gt; links &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; link&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;'click'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleLinkClick&lt;span class=&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 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;
      links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
        link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'click'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleLinkClick&lt;span class=&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 function&quot;&gt;handleLinkClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MouseEvent&lt;span class=&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; link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTarget &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; HTMLAnchorElement
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; href &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'href'&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; target &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'target'&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; url &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;&lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;href &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isInternalLink &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isOpenedInSameWindow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;target &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; target &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'_self'&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isLeftButtonClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;button &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// E.g. Ctrl-clicking a link opens it in a new tab&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// so let the browser handle such clicks&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isModifierKeyPressed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
        event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;altKey &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctrlKey &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metaKey &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shiftKey

      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        isInternalLink &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        isOpenedInSameWindow &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        isLeftButtonClick &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isModifierKeyPressed
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&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;navigate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hash&lt;span class=&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;navigate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ref&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm using &lt;a href=&quot;https://reactrouter.com/docs/en/v6/api#usenavigate&quot; class=&quot;link link-external&quot;&gt;React Router's &lt;code&gt;useNavigate&lt;/code&gt; hook&lt;/a&gt;.
If you don't use React Router,
you can do something similar yourself.
&lt;a href=&quot;https://github.com/remix-run/react-router/blob/v6.3.0/packages/react-router/lib/hooks.tsx#L185-L188&quot; class=&quot;link link-external&quot;&gt;The &lt;code&gt;useNavigate&lt;/code&gt; hook pushes the link to the browser history&lt;/a&gt;
(or replaces instead of pushes, depending on how the hook is used).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;handleLinkClick&lt;/code&gt; function is similar to
&lt;a href=&quot;https://reactrouter.com/docs/en/v6/api#uselinkclickhandler&quot; class=&quot;link link-external&quot;&gt;React Router's &lt;code&gt;useLinkClickHandler&lt;/code&gt; hook&lt;/a&gt;
(which can't be used in this case since it takes a link address as a parameter).&lt;/p&gt;
&lt;h3 id=&quot;usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#usage&quot;&gt;Usage&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-tsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This could come from a content management system (CMS) for example&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myHtml &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* HTML */&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;p&gt;Hello from HTML!&amp;lt;/p&gt;
  &amp;lt;p&gt;
    Here's an internal link:
    &amp;lt;a href=&quot;/foo&quot;&gt;foo&amp;lt;/a&gt;
  &amp;lt;/p&gt;
  &amp;lt;p&gt;
    Another link:
    &amp;lt;a href=&quot;/bar&quot; target=&quot;_blank&quot;&gt;bar&amp;lt;/a&gt;
  &amp;lt;/p&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 keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&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;return&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;&lt;span class=&quot;token class-name&quot;&gt;HtmlContent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;myHtml&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way,
because of the &lt;code&gt;/* HTML */&lt;/code&gt; comment,
&lt;a href=&quot;https://prettier.io/blog/2018/11/07/1.15.0.html#html-template-literal-in-javascript&quot; class=&quot;link link-external&quot;&gt;Prettier formats the template literal as HTML&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-not-attach-a-click-event-listener-to-the-parent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-not-attach-a-click-event-listener-to-the-parent&quot;&gt;Why not attach a click event listener to the parent?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Instead of finding all &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements and attaching click event listeners to them,
you technically &lt;em&gt;could&lt;/em&gt; attach a click event listener only to the parent &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.
In the listener function you could then check if the click was done over a link,
and then handle the link click like in the code above.
Like so:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-tsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; RefObject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useEffect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useRef &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react'&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; useNavigate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react-router-dom'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;HtmlContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; html &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; html&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&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; ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLDivElement&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useLinkClickHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ref&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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;__html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; html &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 class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useLinkClickHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ref&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RefObject&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLDivElement&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 keyword&quot;&gt;const&lt;/span&gt; navigate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useNavigate&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;

    ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&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;'click'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleLinkClick&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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'click'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleLinkClick&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 function&quot;&gt;handleLinkClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MouseEvent&lt;span class=&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; link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; HTMLElement&lt;span class=&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;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Handle link click like in the previous example&lt;/span&gt;
    &lt;span class=&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;navigate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ref&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, &lt;strong&gt;I don't recommend this&lt;/strong&gt;
because it would be &lt;strong&gt;confusing for screen reader users&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Attaching a click event listener to a non-interactive element like &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;
makes some screen readers (e.g. &lt;a href=&quot;https://www.nvaccess.org/&quot; class=&quot;link link-external&quot;&gt;NVDA&lt;/a&gt;)
announce the element as &amp;quot;clickable.&amp;quot;&lt;/p&gt;
&lt;p&gt;In this case,
the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element is not clickable per se
even though a click handler has been attached to it –
the &lt;em&gt;links&lt;/em&gt; are clickable, not the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element –
so announcing the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; as &amp;quot;clickable&amp;quot; is confusing.&lt;/p&gt;
&lt;p&gt;That's way it's better to attach click event listeners to the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements instead.&lt;/p&gt;
&lt;h2 id=&quot;alternative-approach&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#alternative-approach&quot;&gt;Alternative approach&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can use a library like &lt;a href=&quot;https://github.com/remarkablemark/html-react-parser&quot; class=&quot;link link-external&quot;&gt;html-react-parser&lt;/a&gt; or &lt;a href=&quot;https://github.com/pveyes/htmr&quot; class=&quot;link link-external&quot;&gt;htmr&lt;/a&gt;
to convert the HTML string to React components.
&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements could be converted e.g. to &lt;a href=&quot;https://reactrouter.com/docs/en/v6/api#link&quot; class=&quot;link link-external&quot;&gt;React Router's &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; components&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/joi-conditional-multiple-values/</id><title>Joi: checking against multiple values in `conditional()`</title><link href="https://mtsknn.fi/blog/joi-conditional-multiple-values/" /><published>2022-03-09T12:00:00+03:00</published><updated>2022-03-18T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Joi"></category><category term="Testing"></category><content type="html">&lt;p&gt;Use &lt;code&gt;{ is: Joi.any().valid(...values) }&lt;/code&gt;
to check if a value is included in an array.&lt;/p&gt;
&lt;h2 id=&quot;warm-up-problem-no-arrays&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#warm-up-problem-no-arrays&quot;&gt;Warm-up problem (no arrays)&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;You have two values: &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You want to validate the data with these rules:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; is a required string.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;a&lt;/code&gt; equals &lt;code&gt;'foo'&lt;/code&gt;,
&lt;code&gt;b&lt;/code&gt; is a required string;
otherwise &lt;code&gt;b&lt;/code&gt; is forbidden.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;solution-to-the-warm-up-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution-to-the-warm-up-problem&quot;&gt;Solution to the warm-up problem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;a href=&quot;https://joi.dev/api/?v=17.6.0#alternativesconditionalcondition-options&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Joi.alternatives().conditional()&lt;/code&gt;&lt;/a&gt;
to make the validation of &lt;code&gt;b&lt;/code&gt; depend on the value of &lt;code&gt;a&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Joi &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'joi'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; schema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&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;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;b&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alternatives&lt;/span&gt;&lt;span class=&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;conditional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&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;is&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;otherwise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forbidden&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm using &lt;a href=&quot;https://joi.dev/api/?v=17.6.0&quot; class=&quot;link link-external&quot;&gt;Joi 17.6.0&lt;/a&gt; by the way.&lt;/p&gt;
&lt;h2 id=&quot;array-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#array-problem&quot;&gt;Array problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The same problem as above,
but instead of checking if &lt;code&gt;a&lt;/code&gt; equals &lt;code&gt;'foo'&lt;/code&gt;,
we want to check if &lt;code&gt;a&lt;/code&gt; is included in an array:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have two values: &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You want to validate the data with these rules:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; is a required string.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If &lt;code&gt;a&lt;/code&gt; is included in &lt;code&gt;array&lt;/code&gt;,&lt;/strong&gt;
&lt;code&gt;b&lt;/code&gt; is a required string;
otherwise &lt;code&gt;b&lt;/code&gt; is forbidden.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;solution-to-the-array-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution-to-the-array-problem&quot;&gt;Solution to the array problem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We need to change the &lt;code&gt;is&lt;/code&gt; condition.&lt;/p&gt;
&lt;p&gt;To check against multiple values,
use &lt;a href=&quot;https://joi.dev/api/?v=17.6.0#anyvalidvalues---aliases-equal&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Joi.any().valid()&lt;/code&gt; (alias: &lt;code&gt;Joi.any().equal()&lt;/code&gt;)&lt;/a&gt;,
which &amp;quot;adds the provided values into the allowed values list
and marks them as the only valid values allowed&amp;quot;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Joi &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'joi'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; array &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;'foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'baz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; schema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&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;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;b&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alternatives&lt;/span&gt;&lt;span class=&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;conditional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&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;is&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;any&lt;/span&gt;&lt;span class=&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;valid&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;array&lt;span class=&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;then&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;required&lt;/span&gt;&lt;span class=&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;otherwise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forbidden&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example case
it's even better to use &lt;code&gt;string()&lt;/code&gt; instead of &lt;code&gt;any()&lt;/code&gt;
to clarify the intent of the schema:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;any&lt;/span&gt;&lt;span class=&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;valid&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;array&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 class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&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;&lt;span class=&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;valid&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;array&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;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;unit-tests&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#unit-tests&quot;&gt;Unit tests&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wanted to be sure that my conditional Joi schema works,
so I tested it like this using Jest:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; schema &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'./schema'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'schema'&lt;/span&gt;&lt;span class=&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;
  test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'requires `b` if `a` is %s'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;/span&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; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&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; errorMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;details&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;message
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errorMessage&lt;span class=&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;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'&quot;b&quot; is required'&lt;/span&gt;&lt;span class=&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;

  test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'accepts `b` if `a` is %s'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;/span&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; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'fleebles'&lt;/span&gt; &lt;span class=&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;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'error'&lt;/span&gt;&lt;span class=&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;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'forbids `b` if `a` is some other 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 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; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validate&lt;/span&gt;&lt;span class=&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;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'nibbles'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'fleebles'&lt;/span&gt; &lt;span class=&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; errorMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;details&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;message
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errorMessage&lt;span class=&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;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'&quot;b&quot; is not allowed'&lt;/span&gt;&lt;span class=&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;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'accepts missing `b` if `a` is some other 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 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; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validate&lt;/span&gt;&lt;span class=&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;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'nibbles'&lt;/span&gt; &lt;span class=&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;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'error'&lt;/span&gt;&lt;span class=&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;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'accepts undefined `b` if `a` is some other 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 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; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validate&lt;/span&gt;&lt;span class=&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;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'nibbles'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&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;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'error'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result of a test run:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-plain bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;$ NODE_OPTIONS=--experimental-vm-modules npx jest
PASS  ./schema.test.js
  schema
    ✓ requires `b` if `a` is foo
    ✓ requires `b` if `a` is bar
    ✓ requires `b` if `a` is baz
    ✓ accepts `b` if `a` is foo
    ✓ accepts `b` if `a` is bar
    ✓ accepts `b` if `a` is baz
    ✓ forbids `b` if `a` is some other value
    ✓ accepts missing `b` if `a` is some other value
    ✓ accepts undefined `b` if `a` is some other value

Test Suites: 1 passed, 1 total
Tests:       9 passed, 9 total
Snapshots:   0 total
Time:        0.12 s, estimated 1 s
Ran all test suites.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tests are a bit questionable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We depend on specific error messages.
What if they change when Joi is updated?&lt;/li&gt;
&lt;li&gt;We are almost testing that Joi works like it should.
Should we be able to trust that
&lt;code&gt;Joi.alternatives().conditional()&lt;/code&gt; just works?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nonetheless,
I wanted to be sure that my schema works
and these tests do the job for now.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Joi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://joi.dev/api/?v=17.6.0#alternativesconditionalcondition-options&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Joi.alternatives().conditional()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://joi.dev/api/?v=17.6.0#anyvalidvalues---aliases-equal&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Joi.any().valid()&lt;/code&gt; (alias: &lt;code&gt;Joi.any().equal()&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/docs/api#testeachtablename-fn-timeout&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;test.each()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/docs/expect#tohavepropertykeypath-value&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;expect().toHaveProperty()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/docs/ecmascript-modules&quot; class=&quot;link link-external&quot;&gt;Using ES Modules with Jest&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;You might have noticed above that I had to use
&lt;code&gt;NODE_OPTIONS=--experimental-vm-modules npx jest&lt;/code&gt;
instead of just &lt;code&gt;npx jest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/mts-file-extension/</id><title>`.mts` is a cool file extension (TypeScript ES modules)</title><link href="https://mtsknn.fi/blog/mts-file-extension/" /><published>2022-02-09T12:00:00+03:00</published><updated>2022-02-09T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Node.js"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;What's that, a file extension named after me?!
Or a file extension for TypeScript files that are always ES modules?&lt;/p&gt;
&lt;p&gt;I was reading the
&lt;a href=&quot;https://prettier.io/blog/2021/11/25/2.5.0.html&quot; class=&quot;link link-external&quot;&gt;Prettier 2.5 announcement post&lt;/a&gt;
the other day
and noticed that
&amp;quot;Prettier will now format files with &lt;code&gt;.mts&lt;/code&gt; and &lt;code&gt;.cts&lt;/code&gt; extensions as TypeScript.&amp;quot;&lt;/p&gt;
&lt;p&gt;Turns out &lt;code&gt;.mts&lt;/code&gt; is not named after my first name (Matias).
It's for TypeScript files that are always ES modules.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ES modules (ESM) are JavaScript or TypeScript files
that use the &lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt; syntax.&lt;/li&gt;
&lt;li&gt;CommonJS (CJS) modules are JavaScript or TypeScript files
that use the &lt;code&gt;require()&lt;/code&gt;/&lt;code&gt;module.exports&lt;/code&gt; syntax.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require&quot; class=&quot;link link-external&quot;&gt;TypeScript might require special syntax for CommonJS modules&lt;/a&gt;
(I'm not sure).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Usually JavaScript files use the &lt;code&gt;.js&lt;/code&gt; extension
and TypeScript files use the &lt;code&gt;.ts&lt;/code&gt; extension.
Such files can be either ES modules or CommonJS modules.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta/&quot; class=&quot;link link-external&quot;&gt;TypeScript 4.5 Beta announcement post&lt;/a&gt;
explains when the more precise file extensions can be useful
(emphasis added):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Node.js supports
&lt;a href=&quot;https://nodejs.org/api/packages.html#packages_package_json_and_file_extensions&quot; class=&quot;link link-external&quot;&gt;a new setting in &lt;code&gt;package.json&lt;/code&gt; called &lt;code&gt;type&lt;/code&gt;&lt;/a&gt;.
&lt;code&gt;&amp;quot;type&amp;quot;&lt;/code&gt; can be set to either &lt;code&gt;&amp;quot;module&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;commonjs&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This setting controls whether &lt;code&gt;.js&lt;/code&gt; files are interpreted as ES modules or CommonJS modules,
and defaults to CommonJS when not set.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; field in &lt;code&gt;package.json&lt;/code&gt; is nice
because it allows us to continue using the &lt;code&gt;.ts&lt;/code&gt; and &lt;code&gt;.js&lt;/code&gt; file extensions which can be convenient;
however, &lt;strong&gt;you will occasionally need to write a file that differs from what &lt;code&gt;type&lt;/code&gt; specifies.
You might also just prefer to always be explicit.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Node.js supports two extensions to help with this: &lt;code&gt;.mjs&lt;/code&gt; and &lt;code&gt;.cjs&lt;/code&gt;.
&lt;code&gt;.mjs&lt;/code&gt; files are always ES modules,
and &lt;code&gt;.cjs&lt;/code&gt; files are always CommonJS modules,
and there's no way to override these.&lt;/p&gt;
&lt;p&gt;In turn,
TypeScript supports two new source file extensions:
&lt;code&gt;.mts&lt;/code&gt; and &lt;code&gt;.cts&lt;/code&gt;.
When TypeScript emits these to JavaScript files,
it will emit them to &lt;code&gt;.mjs&lt;/code&gt; and &lt;code&gt;.cjs&lt;/code&gt; respectively.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are more details in the first section of the
&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta/&quot; class=&quot;link link-external&quot;&gt;TypeScript 4.5 Beta announcement post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some tools may also require or encourage the more precise file extensions.
An analogy:
&lt;a href=&quot;https://vitejs.dev/&quot; class=&quot;link link-external&quot;&gt;Vite (a build tool)&lt;/a&gt;
supports JSX by default only in &lt;code&gt;.jsx&lt;/code&gt; and &lt;code&gt;.tsx&lt;/code&gt; files
(but not in &lt;code&gt;.js&lt;/code&gt; and &lt;code&gt;.ts&lt;/code&gt; files)
&lt;a href=&quot;https://github.com/vitejs/vite/issues/769#issuecomment-780593283&quot; class=&quot;link link-external&quot;&gt;for performance reasons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Can you think of a file extension that's named after you?&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/react-is-a-framework/</id><title>React is a framework, not a library</title><link href="https://mtsknn.fi/blog/react-is-a-framework/" /><published>2021-10-12T12:00:00+03:00</published><updated>2021-10-12T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;React is marketed as a view library,
but it's more accurately a (view component) framework.&lt;/p&gt;
&lt;h2 id=&quot;react-is-a-framework-because-its-in-control-of-when-your-code-runs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#react-is-a-framework-because-its-in-control-of-when-your-code-runs&quot;&gt;React is a framework because it's in control of when your code runs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A snippet from &lt;a href=&quot;https://gist.github.com/peerreynders/b1e30a4950ca7eed9b2f547f1bf2f151&quot; class=&quot;link link-external&quot;&gt;a GitHub gist by Peer Reynders&lt;/a&gt;
(with minor grammatical edits by me):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The litmus test:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;em&gt;your code calls it&lt;/em&gt;, it's &lt;strong&gt;a library&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;em&gt;it calls your code&lt;/em&gt;, it's &lt;strong&gt;a framework&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking at the React tutorial's&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; Starter Code,
&lt;code&gt;ReactDOM.render()&lt;/code&gt; is the only part of React that &lt;strong&gt;your code calls&lt;/strong&gt;.
The rest, i.e. the majority of your code, &lt;strong&gt;is called by React&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ipso facto&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; – &lt;strong&gt;React is a framework&lt;/strong&gt;
because it is in control when most of your code runs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There you have it.
I have thought for some time that React is a framework, not a library,
but I haven't had the words to explain why.&lt;/p&gt;
&lt;h2 id=&quot;react-vs-jquery&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#react-vs-jquery&quot;&gt;React vs jQuery&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It becomes clearer from Peer's comparison of jQuery (a library) and React (a framework).
Both are &lt;em&gt;tools&lt;/em&gt; for dealing with the DOM,
but they are used differently:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;jQuery for the most part is used as a layer between your code and the browser.
Your code calls jQuery to fulfill some objective –
and when it's done, it's done.
jQuery doesn't do anything until your code calls it the next time.
Some jQuery code may run due to being referenced in an event handler
or because of an async callback,
but that is just in the nature of browser operations.
jQuery as such isn't in control, your code is.
jQuery is called a &lt;em&gt;library&lt;/em&gt; because it's simply a collection of useful helpers;
after you call each method, your code is firmly back in charge.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;ReactDOM.render()&lt;/code&gt; your code hands over control to React.
Past that point React is in full control
and your code only runs when React decides to run it.
React isn't a layer that your code calls to deal with the nitty-gritty of the browser,
but an environment that isolates your components from the browser
and uses your components when it deems it necessary –
which is exactly what a framework does.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;So both jQuery and React stand between your code and the browser('s DOM),
but your code's pattern of interaction with them is &lt;em&gt;very different&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;jQuery is a collection of helpers that your code calls whenever it needs to.&lt;/li&gt;
&lt;li&gt;React on the other hand calls your code. [...]&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/peerreynders/b1e30a4950ca7eed9b2f547f1bf2f151&quot; class=&quot;link link-external&quot;&gt;Go read Peer's GitHub gist&lt;/a&gt;;
it has more great points but isn't too long.&lt;/p&gt;
&lt;h2 id=&quot;does-it-matter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#does-it-matter&quot;&gt;Does it matter?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Does it matter whether React is marketed and thought of as a framework or a library?&lt;/p&gt;
&lt;p&gt;Should React embrace the fact that it's a framework?
Would it affect &lt;a href=&quot;/blog/reacts-ecosystem-is-a-dumb-necessity/&quot; class=&quot;link&quot;&gt;React's ecosystem&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Good questions.
What do &lt;em&gt;you&lt;/em&gt; think?
Send me an email (my address is on the &lt;a href=&quot;/&quot; class=&quot;link&quot;&gt;home page&lt;/a&gt;)
and let me know!&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;Peer is referring to the
&lt;a href=&quot;https://reactjs.org/tutorial/tutorial.html&quot; class=&quot;link link-external&quot;&gt;React tutorial on reactjs.org&lt;/a&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ipso_facto&quot; class=&quot;link link-external&quot;&gt;Wikipedia's definition of &lt;em&gt;ipso facto&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Ipso facto&lt;/strong&gt;&lt;/em&gt; is a Latin phrase,
directly translated as &amp;quot;by the fact itself,&amp;quot;
which means that a specific phenomenon is a &lt;em&gt;direct&lt;/em&gt; consequence,
a resultant &lt;em&gt;effect&lt;/em&gt;,
of the action in question,
instead of being brought about by a previous action.
It is a term of art used in philosophy, law, and science.&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/why-compose-is-right-to-left/</id><title>Why `compose()` is right-to-left</title><link href="https://mtsknn.fi/blog/why-compose-is-right-to-left/" /><published>2021-09-28T12:00:00+03:00</published><updated>2021-09-28T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Functions composed together with &lt;code&gt;compose()&lt;/code&gt;
are called from right to left.
It feels unintuitive at first,
but it's conventional
and kind of makes sense.&lt;/p&gt;
&lt;h2 id=&quot;whats-compose&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-compose&quot;&gt;What's &lt;code&gt;compose()&lt;/code&gt;?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was recently reading the book
&lt;a href=&quot;https://mostly-adequate.gitbook.io/mostly-adequate-guide/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Professor Frisby's Mostly Adequate Guide to Functional Programming [in JavaScript]&lt;/em&gt;&lt;/a&gt;.&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;
(It's a good book,
but became too much for me somewhere around chapter 8 or 9.
&lt;span aria-hidden=&quot;true&quot; class=&quot;whitespace-no-wrap&quot;&gt;¯\(ツ)/¯&lt;/span&gt;)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mostly-adequate.gitbook.io/mostly-adequate-guide/ch05&quot; class=&quot;link link-external&quot;&gt;Chapter 5, &lt;em&gt;Coding by Composing&lt;/em&gt;&lt;/a&gt;,
introduces a &lt;code&gt;compose()&lt;/code&gt; function for composing functions together:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;fns&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 parameter&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&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;
  fns&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduceRight&lt;/span&gt;&lt;span class=&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;res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&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 function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;res&lt;span class=&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; args&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(There's also &lt;a href=&quot;https://ramdajs.com/docs/#compose&quot; class=&quot;link link-external&quot;&gt;Ramda's &lt;code&gt;R.compose&lt;/code&gt;&lt;/a&gt;,
and &lt;a href=&quot;https://lodash.com/docs/#flowRight&quot; class=&quot;link link-external&quot;&gt;Lodash's &lt;code&gt;_.flowRight&lt;/code&gt;&lt;/a&gt;
which is aliased to &lt;code&gt;_.compose&lt;/code&gt; in
&lt;a href=&quot;https://github.com/lodash/lodash/wiki/FP-Guide&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;lodash/fp&lt;/code&gt;&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Example usage from the book:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;toUpperCase&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&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; x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;exclaim&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&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 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;x&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 keyword&quot;&gt;const&lt;/span&gt; shout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;exclaim&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toUpperCase&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;shout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'send in the clowns'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;SEND IN THE CLOWNS!&quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;shout&lt;/code&gt; is a function composed of the &lt;code&gt;exclaim&lt;/code&gt; and &lt;code&gt;toUpperCase&lt;/code&gt; functions:
it first calls &lt;code&gt;toUpperCase&lt;/code&gt; and then &lt;code&gt;exclaim&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Calling &lt;code&gt;shout&lt;/code&gt; is the same as calling the two functions &amp;quot;manually&amp;quot;
(without using &lt;code&gt;compose&lt;/code&gt;):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;exclaim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'send in the clowns'&lt;/span&gt;&lt;span class=&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;// &quot;SEND IN THE CLOWNS!&quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The order of the two functions doesn't matter in this case
because the end result is the same with either order.&lt;/p&gt;
&lt;p&gt;Another example (a bit contrived) from the book;
here the order does matter:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&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; x&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 keyword&quot;&gt;const&lt;/span&gt; reverse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; x&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;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;acc&lt;span class=&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; last &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;head&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reverse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'jumpkick'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'roundhouse'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'uppercut'&lt;/span&gt;&lt;span class=&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;// 'uppercut'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;last&lt;/code&gt; is a function composed of the &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;reverse&lt;/code&gt; functions:
it first calls &lt;code&gt;reverse&lt;/code&gt; and then &lt;code&gt;head&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Again, calling &lt;code&gt;last&lt;/code&gt; is the same as calling the two functions &amp;quot;manually&amp;quot;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;head&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 string&quot;&gt;'jumpkick'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'roundhouse'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'uppercut'&lt;/span&gt;&lt;span class=&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;// 'uppercut'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The order of the two functions matters in this case:
calling &lt;code&gt;head&lt;/code&gt; before &lt;code&gt;reverse&lt;/code&gt; wouldn't work at all because &lt;code&gt;reverse&lt;/code&gt; expects an array.
(If &lt;code&gt;reverse&lt;/code&gt; worked with strings as well,
the result would be &lt;code&gt;'kcikpmuj'&lt;/code&gt;,
which is totally different from &lt;code&gt;'uppercut'&lt;/code&gt;.)&lt;/p&gt;
&lt;h2 id=&quot;why-right-to-left-is-unintuitive&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-right-to-left-is-unintuitive&quot;&gt;Why right-to-left is unintuitive&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you encounter &lt;code&gt;compose()&lt;/code&gt;,
you have to read its arguments backwards.
JavaScript, like most human languages, is written from left to right,
so having to read the arguments backwards is unintuitive.&lt;/p&gt;
&lt;p&gt;When you encounter &lt;code&gt;const myFn = compose(many, args, here)&lt;/code&gt;,
you have to jump to the last argument of &lt;code&gt;compose&lt;/code&gt;
to see what's the first function that &lt;code&gt;myFn&lt;/code&gt; calls,
and then backtrack to the left one argument at a time.&lt;/p&gt;
&lt;p&gt;So, &lt;code&gt;compose(A, B, C)&lt;/code&gt; does not mean &amp;quot;first call &lt;code&gt;A&lt;/code&gt;, then &lt;code&gt;B&lt;/code&gt; and then &lt;code&gt;C&lt;/code&gt;&amp;quot; like one could expect.
It's the opposite: &amp;quot;first call &lt;code&gt;C&lt;/code&gt;, then &lt;code&gt;B&lt;/code&gt; and then &lt;code&gt;A&lt;/code&gt;.&amp;quot; 🤸‍♂️&lt;/p&gt;
&lt;p&gt;Compare also with method chaining, which works from left to right:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token string&quot;&gt;'send in the clowns'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exclaim&lt;/span&gt;&lt;span class=&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;// vs&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;exclaim&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toUpperCase&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'send in the clowns'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'jumpkick'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'roundhouse'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'uppercut'&lt;/span&gt;&lt;span class=&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;head&lt;/span&gt;&lt;span class=&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;// vs&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;head&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reverse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'jumpkick'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'roundhouse'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'uppercut'&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;why-right-to-left-makes-sense-kind-of&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-right-to-left-makes-sense-kind-of&quot;&gt;Why right-to-left makes sense (kind of)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The book justifies the right-to-left order very shallowly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We could define a left to right version,
however,
we mirror the mathematical version much more closely as it stands.
That's right,
composition is straight from the math books.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's been too long since high school math,
so I had to look up
&lt;a href=&quot;https://en.wikipedia.org/wiki/Function_composition&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Function composition (mathematical concept)&lt;/em&gt; on Wikipedia&lt;/a&gt;.
An example&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;(𝑓∘𝑔∘ℎ)(𝑧) = 𝑓(𝑔(ℎ(𝑧)))&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Notice how the order of the functions 𝑓, 𝑔 and ℎ
is the same on both sides of the equals sign.&lt;/p&gt;
&lt;p&gt;This is true in JavaScript as well:
&lt;code&gt;compose(A, B, C)(arg)&lt;/code&gt; is the same as &lt;code&gt;A(B(C(arg)))&lt;/code&gt;.
Put more visually:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//      ↓  ↓  ↓  ↓↓↓&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; arg &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you think of &lt;code&gt;compose()&lt;/code&gt; this way,
it &lt;em&gt;kind of&lt;/em&gt; makes sense.&lt;/p&gt;
&lt;h2 id=&quot;pipe-is-left-to-right-and-more-intuitive&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pipe-is-left-to-right-and-more-intuitive&quot;&gt;&lt;code&gt;pipe()&lt;/code&gt; is left-to-right and more intuitive&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &amp;quot;left-to-right &lt;code&gt;compose()&lt;/code&gt;&amp;quot; is called &lt;code&gt;pipe()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example,
&lt;a href=&quot;https://ramdajs.com/docs/#pipe&quot; class=&quot;link link-external&quot;&gt;Ramda has &lt;code&gt;R.pipe&lt;/code&gt;&lt;/a&gt;,
and &lt;a href=&quot;https://lodash.com/docs/#flow&quot; class=&quot;link link-external&quot;&gt;Lodash has &lt;code&gt;_.flow&lt;/code&gt;&lt;/a&gt;
which is aliased to &lt;code&gt;_.pipe&lt;/code&gt; in
&lt;a href=&quot;https://github.com/lodash/lodash/wiki/FP-Guide&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;lodash/fp&lt;/code&gt;&lt;/a&gt;.
There's also an
&lt;a href=&quot;https://github.com/tc39/proposal-pipeline-operator&quot; class=&quot;link link-external&quot;&gt;ECMAScript proposal for adding a pipe/pipeline operator (&lt;code&gt;|&amp;gt;&lt;/code&gt;) to JavaScript&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;An example from Ramda's documentation:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; f &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;negate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// -(3^4) + 1&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare with &lt;code&gt;R.compose&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; f &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;negate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// -(3^4) + 1&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Piping is so much more intuitive that
I wonder what are the arguments for favoring &lt;code&gt;compose&lt;/code&gt;.
&amp;quot;That's how it works in math&amp;quot; is one argument,
but how good an argument is it?
If you know other arguments,
please tell me!&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;The book is licensed under a
&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0/&quot; class=&quot;link link-external&quot;&gt;CC BY-SA 4.0 license&lt;/a&gt;.
Some code samples on this page are from the book;
I have formatted them with Prettier. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;I was wondering why I couldn't find a Unicode symbol for
&amp;quot;mathematical italic small h&amp;quot; (ℎ)
even though I could find symbols for
&amp;quot;mathematical italic small f&amp;quot; (𝑓)
and
&amp;quot;mathematical italic small g&amp;quot; (𝑔).
Apparently because
when the Unicode symbols for mathematical italic small letters were defined,
ℎ had already a different name for it: &amp;quot;Planck constant.&amp;quot;
Interesting!
Source:
&lt;a href=&quot;https://stackoverflow.com/q/47206070/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Why are there holes in the Unicode table?&lt;/em&gt; on Stack Overflow&lt;/a&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/periods-and-commas-belong-inside-quotes-in-american-english/</id><title>Periods and commas belong inside quotes in American English</title><link href="https://mtsknn.fi/blog/periods-and-commas-belong-inside-quotes-in-american-english/" /><published>2021-09-25T12:00:00+03:00</published><updated>2021-09-25T12:00:00+03:00</updated><category term="English"></category><content type="html">&lt;p&gt;Like so: &amp;quot;The name's Bourne,&amp;quot; the man said, &amp;quot;JSON Bourne.&amp;quot;
Also when quoting single words,
like &amp;quot;nibbles,&amp;quot; &amp;quot;gronk&amp;quot; and &amp;quot;fleebles.&amp;quot;&lt;/p&gt;
&lt;p&gt;Why?
Because it's a rule.
Some sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thepunctuationguide.com/quotation-marks.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Quotation marks&lt;/em&gt; on The Punctuation Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://grammar.yourdictionary.com/grammar/punctuation/does-punctuation-go-inside-quotation-marks.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Does Punctuation Go Inside Quotation Marks?&lt;/em&gt; on YourDictionary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://style.mla.org/punctuation-and-quotation-marks/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Why do periods and commas go inside quotation marks in MLA style?&lt;/em&gt; on MLA Style Center&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are not convinced,
consult your favorite style guide.&lt;/p&gt;
&lt;p&gt;I write mainly American English.
I avoid mixing in other flavors, like British English,
to keep my English consistent.&lt;/p&gt;
&lt;h2 id=&quot;an-exception-to-the-rule&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#an-exception-to-the-rule&quot;&gt;An exception to the rule&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Place periods and commas outside the quotes
if placing them inside the quotes
could make the text ambiguous or lead to errors,
e.g. when quoting user inputs.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The password is &amp;quot;hunter2.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The above is ambiguous:
does the password include the period or not?&lt;/p&gt;
&lt;p&gt;Compare with this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The password is &amp;quot;hunter2&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The above is unambiguous and thus preferable.&lt;/p&gt;
&lt;p&gt;Sometimes it's better to change the sentence structure to avoid this problem.&lt;/p&gt;
&lt;p&gt;I don't know if this exception is actually allowed in American English,
but it's common sense.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/reacts-ecosystem-is-a-dumb-necessity/</id><title>React's ecosystem is a dumb necessity</title><link href="https://mtsknn.fi/blog/reacts-ecosystem-is-a-dumb-necessity/" /><published>2021-09-15T12:00:00+03:00</published><updated>2021-10-12T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mithril.js"></category><category term="Rant"></category><category term="React"></category><content type="html">&lt;p&gt;React's ecosystem is large,
which is a good thing:
lot's of great libraries to use.
But it's also a bad thing:
most of those libraries are compatible only with React.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/jfbrennan/comment/1712b&quot; class=&quot;link link-external&quot;&gt;Jordan Brennan's comment on dev.to&lt;/a&gt;
beautifully sums up the downsides:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;React's ecosystem is not a benefit.
It's a dumb necessity grown from the need to create more stuff,
much of it being React-only versions of existing stuff,
because React is so incompatible and fussy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And part of &lt;a href=&quot;https://dev.to/jfbrennan/comment/1h007&quot; class=&quot;link link-external&quot;&gt;Jordan's another comment&lt;/a&gt;
as well:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A large ecosystem is not a benefit.
It is a sign that the library is too finicky and non-standard
to play nice with the thousands of other libraries out there,
hence all the special React versions of those libraries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words:
integrating vanilla JS libraries with React is difficult,
so people create React-only libraries (&lt;code&gt;react-this&lt;/code&gt;, &lt;code&gt;react-that&lt;/code&gt; etc.).&lt;/p&gt;
&lt;p&gt;What I'd prefer:
integrating vanilla JS libraries with React is easy,
so people don't need to create React-only libraries.
Most effort and focus can be put to creating and improving vanilla JS libraries,
and those libraries can easily be used with &lt;em&gt;and without&lt;/em&gt; React.
Win-win!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://mithril.js.org/&quot; class=&quot;link link-external&quot;&gt;Mithril.js&lt;/a&gt;,
a front-end framework with some similarities to React,
takes a different approach.
Its documentation has a dedicated (though currently very brief) page about
&lt;a href=&quot;https://mithril.js.org/integrating-libs.html&quot; class=&quot;link link-external&quot;&gt;integrating 3rd party libraries/code with Mithril.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It would be nice if React had a similar mindset and similar capabilities.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/scheduling-vacations-for-maximal-relaxation/</id><title>Scheduling vacations for maximal relaxation</title><link href="https://mtsknn.fi/blog/scheduling-vacations-for-maximal-relaxation/" /><published>2021-08-27T12:00:00+03:00</published><updated>2021-08-27T12:00:00+03:00</updated><category term="Work–life balance"></category><content type="html">&lt;p&gt;Try to schedule vacations
so that they start and end in the middle of the week.
You'll get two short work weeks around the vacation.&lt;/p&gt;
&lt;p&gt;If your vacation starts in the middle of the week,
the work week before the vacation will be a short one,
so you won't be totally exhausted on the first day (Saturday) of the vacation.&lt;/p&gt;
&lt;p&gt;If your vacation ends in the middle of the week,
the first work week after the vacation will be more pleasant
as it will be a short one.
Returning from vacation won't be as stressful
as you know you'll have to endure only two or three days before the weekend.&lt;/p&gt;
&lt;p&gt;&amp;quot;Endure&amp;quot; only two or three days...?
Maximize laziness
and minimize work...?&lt;/p&gt;
&lt;p&gt;Well yes, but actually no.&lt;/p&gt;
&lt;p&gt;You see,
a relaxed worker
is a happy and productive worker.
Win-win!&lt;/p&gt;
&lt;p&gt;I learned this trick some years ago from my colleague.
Thanks, Joonas!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/jsx-vs-htm-hyperscript-tagged-markup/</id><title>JSX vs HTM (Hyperscript Tagged Markup)</title><link href="https://mtsknn.fi/blog/jsx-vs-htm-hyperscript-tagged-markup/" /><published>2021-08-23T12:00:00+03:00</published><updated>2022-04-10T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;HTM provides a transpiler-free alternative to JSX via tagged templates.
HTM has some limitations,
but can be used in browsers
and can be good for smaller projects.&lt;/p&gt;
&lt;h2 id=&quot;jsx&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#jsx&quot;&gt;JSX&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JSX is a syntax extension to JavaScript.
It's transpiled away before it's served to the browser.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// JSX:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&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;foo&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 plain-text&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Output:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'div'&lt;/span&gt;&lt;span class=&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;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'foo'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSX is the default choice in like 99% of React projects.
It's not a pro or a con per se,
but it raises the question:
why wouldn't I just use JSX instead of some alternative?&lt;/p&gt;
&lt;h3 id=&quot;jsx-pros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#jsx-pros&quot;&gt;JSX pros&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Great editor support&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Syntax highlighting.&lt;/li&gt;
&lt;li&gt;IntelliSense, with or without TypeScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Syntax errors are actual errors&lt;/h4&gt;
&lt;p&gt;The transpiler won't let syntax errors pass.
This is better than HTM failing silently on errors.&lt;/p&gt;
&lt;h4&gt;ESLint plugins&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yannickcr/eslint-plugin-react&quot; class=&quot;link link-external&quot;&gt;eslint-plugin-react: React-specific rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jsx-eslint/eslint-plugin-jsx-a11y&quot; class=&quot;link link-external&quot;&gt;eslint-plugin-jsx-a11y: accessibility rules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Great Prettier support&lt;/h4&gt;
&lt;p&gt;Prettier works better with JSX than with HTM,
as we'll see below.&lt;/p&gt;
&lt;h4&gt;0 bytes and no runtime overhead&lt;/h4&gt;
&lt;p&gt;JSX is transpiled away.&lt;/p&gt;
&lt;h4&gt;Shorthand syntax for fragments&lt;/h4&gt;
&lt;p&gt;I.e. &lt;code&gt;&amp;lt;&amp;gt;...&amp;lt;/&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;jsx-cons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#jsx-cons&quot;&gt;JSX cons&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Needs a transpiler&lt;/h4&gt;
&lt;p&gt;More tooling = more things to setup and maintain.&lt;/p&gt;
&lt;p&gt;Babel can be run in the browser,
but that would be slow.&lt;/p&gt;
&lt;h4&gt;New syntax to learn&lt;/h4&gt;
&lt;p&gt;JSX is not regular JavaScript;
it's a &lt;em&gt;syntax extension&lt;/em&gt; to JavaScript.&lt;/p&gt;
&lt;p&gt;Personally I have no problems with the JSX syntax,
but I have seen some people struggling with it:
when to use curly braces etc.&lt;/p&gt;
&lt;h2 id=&quot;htm&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#htm&quot;&gt;HTM&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/developit/htm&quot; class=&quot;link link-external&quot;&gt;HTM (Hyperscript Tagged Markup)&lt;/a&gt; is a JS library
that provides a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates&quot; class=&quot;link link-external&quot;&gt;tagged template&lt;/a&gt;
for writing JSX-like markup.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; html &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'htm/react'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;div className=&quot;foo&quot;&gt;bar&amp;lt;/div&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;htm-pros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#htm-pros&quot;&gt;HTM pros&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;No transpiler needed&lt;/h4&gt;
&lt;p&gt;Implications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can be run in the browser.&lt;/li&gt;
&lt;li&gt;Less tooling to setup and maintain.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTM is tiny and fast&lt;/h4&gt;
&lt;p&gt;Thus it's OK to use HTM in the browser,
at least during development.
Probably in production as well
(just get started and optimize performance later if needed!).&lt;/p&gt;
&lt;h4&gt;0 bytes and no runtime overhead if compiled away&lt;/h4&gt;
&lt;p&gt;For production builds,
consider compiling HTM away using &lt;a href=&quot;https://github.com/developit/htm/tree/master/packages/babel-plugin-htm&quot; class=&quot;link link-external&quot;&gt;babel-plugin-htm&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;No new JavaScript syntax to learn&lt;/h4&gt;
&lt;p&gt;HTM is just standard &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates&quot; class=&quot;link link-external&quot;&gt;tagged templates&lt;/a&gt;,
i.e. regular JavaScript
(as opposed to JSX, which is a syntax extension to JavaScript).&lt;/p&gt;
&lt;p&gt;HTM needs to be used in a certain way,
so you do need to learn &amp;quot;HTM syntax,&amp;quot;
but no &lt;em&gt;new JavaScript syntax&lt;/em&gt;.&lt;/p&gt;
&lt;h4&gt;Syntax highlighting support in editors&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/developit/htm&quot; class=&quot;link link-external&quot;&gt;See HTM's readme for an up-to-date list of editor extensions/plugins&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;OK Prettier support&lt;/h4&gt;
&lt;p&gt;Prettier supports HTM, and that's great.
I wouldn't personally even consider using HTM if Prettier didn't support it.&lt;/p&gt;
&lt;p&gt;But the outcome is not always very pretty,
as we'll see below.&lt;/p&gt;
&lt;p&gt;I recommend setting
&lt;a href=&quot;https://prettier.io/docs/en/options.html#html-whitespace-sensitivity&quot; class=&quot;link link-external&quot;&gt;Prettier's &lt;code&gt;htmlWhitespaceSensitivity&lt;/code&gt; option&lt;/a&gt;
to &lt;code&gt;'ignore'&lt;/code&gt;
because HTM strips (most) extra whitespace away like JSX does.
(There might be some differences between how HTM and JSX handle whitespace;
pay attention.)&lt;/p&gt;
&lt;h4&gt;Shorthand syntax for components' closing tags&lt;/h4&gt;
&lt;p&gt;E.g. &lt;code&gt;&amp;lt;${Footer}&amp;gt;content&amp;lt;//&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Using the shorthand much can make things hard to read,
but it might anyway be better to split large components into smaller pieces.&lt;/p&gt;
&lt;h4&gt;Supports HTML-like comments&lt;/h4&gt;
&lt;p&gt;E.g. &lt;code&gt;&amp;lt;!-- Hey there --&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;HTML-like comments are stripped out,
which is a good or a bad thing depending on the situation.&lt;/p&gt;
&lt;h4&gt;Implicit fragments&lt;/h4&gt;
&lt;p&gt;Returning &lt;code&gt;html`&amp;lt;div /&amp;gt;&amp;lt;div /&amp;gt;`&lt;/code&gt; automatically wraps the two &lt;code&gt;div&lt;/code&gt;s inside a fragment.
Or actually an array:
&lt;a href=&quot;https://github.com/developit/htm/issues/175&quot; class=&quot;link link-external&quot;&gt;HTM issue #175 on GitHub is about implicit fragments&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;htm-cons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#htm-cons&quot;&gt;HTM cons&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Fails silently on syntax errors&lt;/h4&gt;
&lt;p&gt;This can cause some head scratching.
Related issues on GitHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/56&quot; class=&quot;link link-external&quot;&gt;HTM issue #56&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/122&quot; class=&quot;link link-external&quot;&gt;HTM issue #122&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/166&quot; class=&quot;link link-external&quot;&gt;HTM issue #166&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/168&quot; class=&quot;link link-external&quot;&gt;HTM issue #168&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/208&quot; class=&quot;link link-external&quot;&gt;HTM issue #208&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;No IntelliSense or TypeScript support&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/73&quot; class=&quot;link link-external&quot;&gt;HTM issue #73 on GitHub is about TypeScript support.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;On the other hand,
if you use TypeScript,
why not just use TSX?
It's compiled away.&lt;/p&gt;
&lt;h4&gt;No ESLint plugins&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/183&quot; class=&quot;link link-external&quot;&gt;HTM issue #183 on GitHub is a feature request for an ESLint plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/198&quot; class=&quot;link link-external&quot;&gt;HTM issue #198 on GitHub is about eslint-plugin-jsx-a11y&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Prettier quirk: &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; tags are wonky&lt;/h4&gt;
&lt;p&gt;As mentioned above,
HTM strips (most) extra whitespace away like JSX does.&lt;/p&gt;
&lt;p&gt;However,
inside &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; tags Prettier treats some non-significant whitespace as significant,
so the indentation can get really wonky.&lt;/p&gt;
&lt;p&gt;Example (tested with Prettier 2.2.0 and 2.6.2);
I have borked the indentation quite much for illustrative purposes:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This code is formatted with Prettier but is very ugly!&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;pre&gt;
 &amp;lt;code   className=&quot;foo&quot;    dangerouslySetInnerHTML=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;highlightedCode
    &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;__html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; highlightedCode &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;undefined&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;
&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;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;highlightedCode &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; plainCode&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;

    &amp;lt;/code  &gt;
     &amp;lt;/pre&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Workaround: use &lt;code&gt;&amp;lt;${'pre'}&amp;gt;&lt;/code&gt; instead!
Then Prettier won't treat non-significant whitespace as significant.
Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This code is formatted with Prettier, looks OK&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;&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 string&quot;&gt;'pre'&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;&gt;
    &amp;lt;code
      className=&quot;foo&quot;
      dangerouslySetInnerHTML=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;highlightedCode
        &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;__html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; highlightedCode &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;undefined&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;
    &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;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;highlightedCode &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; plainCode&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    &amp;lt;/code&gt;
  &amp;lt;//&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSX for comparison (better formatting in my opinion):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This code is formatted with Prettier, looks beautiful!&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;pre&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;code&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;className&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;foo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        highlightedCode &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;__html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; highlightedCode &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;undefined&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&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;highlightedCode &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; plainCode&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;pre&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;em&gt;Obsolete:&lt;/em&gt; Prettier quirk: consecutive &lt;code&gt;${expressions}&lt;/code&gt; can be messy&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt;
I noticed that Prettier has this quirk only when formatting JS code blocks in Markdown files,
not when formatting JS files.
My bad!&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Example of messy consecutive &lt;code&gt;${expressions}&lt;/code&gt; (click to toggle)&lt;/summary&gt;
&lt;p&gt;Tested with Prettier 2.2.0 and 2.6.2;
notice how the two expressions end/start on the same line
(but only when formatting a JS code block in a Markdown file!):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;div&gt;
    &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;foo &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;p&gt;Foo...&amp;lt;/p&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 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;bar &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;p&gt;Bar...&amp;lt;/p&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 interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;/div&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;h4&gt;Having to repeat &lt;code&gt;html`...`&lt;/code&gt; is tedious&lt;/h4&gt;
&lt;p&gt;E.g. when mapping arrays
or with conditional rendering.&lt;/p&gt;
&lt;p&gt;I also dislike how Prettier spans the code on many more lines than with JSX.&lt;/p&gt;
&lt;p&gt;Contrived example:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;ul&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;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;li&gt;No items&amp;lt;/li&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 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;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;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; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
        &amp;lt;li key=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&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;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/li&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 interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;/ul&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSX for comparison (much more compact):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;No items&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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 plain-text&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;HTML entities are escaped&lt;/h4&gt;
&lt;p&gt;For example,
the text inside
&lt;code&gt;html`&amp;lt;span&amp;gt;1&amp;amp;ndash;2&amp;lt;/span&amp;gt;`&lt;/code&gt;
gets rendered as
&lt;code&gt;1&amp;amp;ndash;2&lt;/code&gt;
instead of
&lt;code&gt;1–2&lt;/code&gt;.
(&lt;code&gt;&amp;amp;ndash;&lt;/code&gt; = en dash.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/developit/htm/issues/76&quot; class=&quot;link link-external&quot;&gt;HTM issue #76 on GitHub is about how HTML entities are handled.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This makes it more difficult to use special characters in components' text contents.
You could type them out as-is,
but having special characters in source code is bad
because it can be difficult to distinguish between similar characters.
For example between
&lt;code&gt;-&lt;/code&gt; (hyphen),
&lt;code&gt;–&lt;/code&gt; (en dash)
and &lt;code&gt;—&lt;/code&gt; (em dash).&lt;/p&gt;
&lt;p&gt;A workaround is to create e.g. &lt;code&gt;char.js&lt;/code&gt; and use it like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// char.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;ndash&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&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;mdash&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'—'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Component.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; char &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'./char.js'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token 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; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;span&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;char&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ndash&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;2&amp;lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;No support for comments inside opening/closing tags&lt;/h4&gt;
&lt;p&gt;HTM supports only HTML-like comments,
so you can't comment specific props or attributes.&lt;/p&gt;
&lt;p&gt;In JSX you can comment props and attributes:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;button&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;className&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;foo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;disabled&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Disabled because x&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;id&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;bar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Using `baz` instead of `qux` because y&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;baz&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;
  Click me
&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Can't use backticks in comments&lt;/h4&gt;
&lt;p&gt;Or they can be used
but have to be escaped.&lt;/p&gt;
&lt;p&gt;Backticks would be useful when referring to variables in comments.
Escaped backticks and single quotes look silly:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;div&gt;
    &amp;lt;!-- 'foo' is something --&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;foo&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;

    &amp;lt;!-- But \`bar\` is something else --&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;bar&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;/div&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSX for comparison:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* `foo` is something */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* But `bar` is something else */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;bar&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;verdict&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#verdict&quot;&gt;Verdict&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like the idea of HTM a lot:
it's just JavaScript tagged templates,
so there's no need for a transpiler
and no need to learn new JavaScript syntax.&lt;/p&gt;
&lt;p&gt;HTM can be a good choice for browser environments
(when you can't or don't want to use a transpiler)
and for smaller projects.&lt;/p&gt;
&lt;p&gt;The limitations of HTM
(no IntelliSense, no ESLint plugins, etc.)
can however become too limiting in bigger projects.
Or at least I would imagine so,
I haven't used HTM in any large projects.&lt;/p&gt;
&lt;p&gt;Here's my non-prescriptive rules for choosing between JSX and HTM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Choose HTM if:
&lt;ol&gt;
&lt;li&gt;You can't or don't want to use a transpiler.&lt;/li&gt;
&lt;li&gt;You can live without IntelliSense and ESLint plugins.&lt;/li&gt;
&lt;li&gt;Optional: you struggle with JSX syntax.
(In comparison, HTM is just JavaScript.)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Otherwise choose JSX.
It requires a transpiler,
but JSX is really robust.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But hey,
what about
&lt;a href=&quot;https://mtsknn.fi/blog/hyperscript-hyperior-alternative-to-jsx/&quot; class=&quot;link&quot;&gt;another JSX alternative, hyperscript&lt;/a&gt;...?
I'll leave the decision to you. 😁&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/fizzbuzz-in-javascript-with-infinite-arrays-and-multimapping/</id><title>FizzBuzz in JavaScript with infinite arrays and multimapping</title><link href="https://mtsknn.fi/blog/fizzbuzz-in-javascript-with-infinite-arrays-and-multimapping/" /><published>2021-08-14T12:00:00+03:00</published><updated>2021-08-14T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Fun way to solve the simple puzzle.
Infinitely repeating arrays
and mapping over multiple arrays
almost makes the remainder/modulo operator (&lt;code&gt;%&lt;/code&gt;) unnecessary.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#tldr&quot;&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;#finished-result-playground&quot; class=&quot;link link-anchor&quot;&gt;Jump to the &lt;em&gt;Finished result + playground&lt;/em&gt; section →&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rules-of-fizzbuzz&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#rules-of-fizzbuzz&quot;&gt;Rules of FizzBuzz&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A FizzBuzz sequence consists of numbers and strings where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;every 3rd item is &amp;quot;Fizz&amp;quot;&lt;/li&gt;
&lt;li&gt;every 5th item is &amp;quot;Buzz&amp;quot;&lt;/li&gt;
&lt;li&gt;every 15th item is &amp;quot;FizzBuzz&amp;quot;&lt;/li&gt;
&lt;li&gt;and other items are numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the first 15 items are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;1&lt;/li&gt;
&lt;li&gt;2&lt;/li&gt;
&lt;li&gt;Fizz&lt;/li&gt;
&lt;li&gt;4&lt;/li&gt;
&lt;li&gt;Buzz&lt;/li&gt;
&lt;li&gt;Fizz&lt;/li&gt;
&lt;li&gt;7&lt;/li&gt;
&lt;li&gt;8&lt;/li&gt;
&lt;li&gt;Fizz&lt;/li&gt;
&lt;li&gt;Buzz&lt;/li&gt;
&lt;li&gt;11&lt;/li&gt;
&lt;li&gt;Fizz&lt;/li&gt;
&lt;li&gt;13&lt;/li&gt;
&lt;li&gt;14&lt;/li&gt;
&lt;li&gt;FizzBuzz&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After that,
the cycle repeats.
(The 16th item is 16 instead of 1,
and so on.)&lt;/p&gt;
&lt;h2 id=&quot;the-challenge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-challenge&quot;&gt;The challenge&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here's a typical solution, though without a &lt;code&gt;for&lt;/code&gt; loop:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&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 parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'FizzBuzz'&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; n
&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;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//        1,      2, 'Fizz',      4,     'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   'Fizz',      7,      8, 'Fizz',     'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       11, 'Fizz',     13,     14, 'FizzBuzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works a-okay,
but &lt;strong&gt;let's solve FizzBuzz without using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder&quot; class=&quot;link link-external&quot;&gt;remainder operator&lt;/a&gt; in the usual way&lt;/strong&gt;,
i.e. without these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if (n % 15 === 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if (n % 3 === 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if (n % 5 === 0)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before that,
we need to acquire two new skills:
creating infinite arrays
and mapping over multiple arrays.&lt;/p&gt;
&lt;h2 id=&quot;infinite-arrays&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#infinite-arrays&quot;&gt;Infinite arrays&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;How arrays normally work (d'oh):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; array &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;'A'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'B'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'C'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token comment&quot;&gt;//=&gt; 3&lt;/span&gt;

array&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 comment&quot;&gt;//=&gt; 'A'&lt;/span&gt;
array&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 comment&quot;&gt;//=&gt; 'B'&lt;/span&gt;
array&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 comment&quot;&gt;//=&gt; 'C'&lt;/span&gt;
array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; undefined&lt;/span&gt;
array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; undefined&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we want:
when accessing an out-of-bounds numeric property of the &lt;code&gt;array&lt;/code&gt; object,
cycle back to the beginning of the array.&lt;/p&gt;
&lt;p&gt;That can be achieved by creating
a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Proxy&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; proxyHandler &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 function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; prop&lt;span class=&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;// Accessing `target.length`&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'length'&lt;/span&gt;&lt;span class=&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 number&quot;&gt;Infinity&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Accessing a numeric property of `target`, e.g. `target[5]`&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; prop &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'string'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&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;^\d+$&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop&lt;span class=&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;return&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&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;// Accessing whatever else, e.g. `target.foo`&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;cycle&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; proxyHandler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I named the function &lt;code&gt;cycle&lt;/code&gt;
because I was inspired by
&lt;a href=&quot;https://clojuredocs.org/clojure.core/cycle&quot; class=&quot;link link-external&quot;&gt;Clojure's &lt;code&gt;cycle&lt;/code&gt; function&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; infiniteArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'A'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'B'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'C'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

infiniteArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token comment&quot;&gt;//=&gt; Infinity&lt;/span&gt;

infiniteArray&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 comment&quot;&gt;//=&gt; 'A'&lt;/span&gt;
infiniteArray&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 comment&quot;&gt;//=&gt; 'B'&lt;/span&gt;
infiniteArray&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 comment&quot;&gt;//=&gt; 'C'&lt;/span&gt;
infiniteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 'A'&lt;/span&gt;
infiniteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 'B'&lt;/span&gt;
infiniteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 'C'&lt;/span&gt;
infiniteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 'A'&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;notes-about-the-typeof-prop-check&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#notes-about-the-typeof-prop-check&quot;&gt;Notes about the &lt;code&gt;typeof prop&lt;/code&gt; check&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Why is the &lt;code&gt;typeof prop === 'string'&lt;/code&gt; check in the proxy handler's &lt;code&gt;get&lt;/code&gt; method needed?&lt;/h4&gt;
&lt;p&gt;Otherwise the regex test would throw an error
if &lt;code&gt;prop&lt;/code&gt; was a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol&quot; class=&quot;link link-external&quot;&gt;Symbol&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example,
if &lt;code&gt;prop&lt;/code&gt; was
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Symbol.iterator&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^\d+$&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Symbol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;iterator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Cannot convert a Symbol value to a string&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error is thrown
because &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;RegExp.prototype.test&lt;/code&gt;&lt;/a&gt;
expects a string argument,
and Symbols can't be implicitly converted to strings.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Symbol.iterator&lt;/code&gt; is used by &lt;code&gt;for...of&lt;/code&gt; loops.
So,
using &lt;code&gt;infiniteArray&lt;/code&gt; in a &lt;code&gt;for...of&lt;/code&gt; loop
would thus throw an error
without the &lt;code&gt;typeof&lt;/code&gt; check.&lt;/p&gt;
&lt;p&gt;Using any other Symbol property key would throw as well
without the &lt;code&gt;typeof&lt;/code&gt; check.&lt;/p&gt;
&lt;h4&gt;Why check that &lt;code&gt;typeof prop&lt;/code&gt; is &lt;code&gt;'string'&lt;/code&gt; instead of &lt;code&gt;'number'&lt;/code&gt;?&lt;/h4&gt;
&lt;p&gt;E.g. in &lt;code&gt;infiniteArray[5]&lt;/code&gt; the property key is a number, right?
Well yes, but actually no.&lt;/p&gt;
&lt;p&gt;Numeric property keys are converted to strings.
From &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Working with objects&lt;/em&gt; on MDN&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All keys in the square bracket notation are converted to string
unless they're Symbols,
since JavaScript object property names (keys)
can only be strings or Symbols.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;An alternative to the &lt;code&gt;typeof prop&lt;/code&gt; check&lt;/h4&gt;
&lt;p&gt;I said above that Symbols can't be &lt;em&gt;implicitly&lt;/em&gt; converted to strings.
But a Symbol can be converted &lt;em&gt;explicitly&lt;/em&gt; to a string by calling its &lt;code&gt;toString()&lt;/code&gt; method.
Doing so would make the &lt;code&gt;typeof prop&lt;/code&gt; check unnecessary:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; prop &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'string'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&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;^\d+$&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop&lt;span class=&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&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;^\d+$&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Neither option is very clear without an explanation.
I might prefer the &lt;code&gt;toString()&lt;/code&gt; alternative.&lt;/p&gt;
&lt;h3 id=&quot;shortcomings&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#shortcomings&quot;&gt;Shortcomings&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;cycle&lt;/code&gt; function is imperfect.
For example,
slicing doesn't work:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; infiniteArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'A'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'B'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'C'&lt;/span&gt;&lt;span class=&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;// Current behavior:&lt;/span&gt;
infiniteArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['A', 'B', 'C', empty × 4]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Ideal behavior:&lt;/span&gt;
infiniteArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['A', 'B', 'C', 'A', 'B', 'C', 'A']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Supporting all array methods would be interesting.
I'll leave it to you as an exercise.&lt;/p&gt;
&lt;p&gt;The current imperfect implementation is enough for solving FizzBuzz,
so let's proceed.&lt;/p&gt;
&lt;h2 id=&quot;multimapping&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#multimapping&quot;&gt;Multimapping&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://clojuredocs.org/clojure.core/map&quot; class=&quot;link link-external&quot;&gt;Clojure's &lt;code&gt;map&lt;/code&gt; function&lt;/a&gt;
is similar to
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot; class=&quot;link link-external&quot;&gt;JavaScript arrays' &lt;code&gt;map&lt;/code&gt; method&lt;/a&gt;,
except in Clojure you can map over multiple arrays at once:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;map&lt;/code&gt; returns a lazy sequence consisting of the result of
applying [the function] &lt;code&gt;f&lt;/code&gt; to the set of first items of each &lt;code&gt;coll&lt;/code&gt;,
followed by applying &lt;code&gt;f&lt;/code&gt; to the set of second items in each &lt;code&gt;coll&lt;/code&gt;,
until any one of the &lt;code&gt;coll&lt;/code&gt;s is exhausted.
Any remaining items in other &lt;code&gt;coll&lt;/code&gt;s are ignored.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A &lt;code&gt;multimap&lt;/code&gt; function can be implemented in a few lines of JavaScript
(I'm ignoring the part about returning a lazy sequence):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;multimap&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;arrays&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; arrayLengths &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arrays&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&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; array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; smallestArrayLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&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;arrayLengths&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; smallestArrayLength &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arrays&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&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; array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&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 function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Same lenghts -&gt; loop over 4 times&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &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;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; i
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'A'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'B'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'C'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'D'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'W'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'X'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Y'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Z'&lt;/span&gt;&lt;span class=&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;// Console loggings:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   0, ['A', 'W']&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   1, ['B', 'X']&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   2, ['C', 'Y']&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   3, ['D', 'Z']&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Return value:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [0, 1, 2, 3]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Different lengths -&gt; loop over 3 times (the length of the shortest array)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &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;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&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 string&quot;&gt;'♠'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'♡'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'♢'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&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 string&quot;&gt;'A'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'B'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'C'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'D'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'E'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'♪'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'♫'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&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;// Console loggings:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   0, ['♠', 'A', '♪']&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   1, ['♡', 'B', '♫']&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   2, ['♢', 'C', '☻']&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Return value:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ['♠', 'B', '☻']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;putting-the-pieces-together-solving-fizzbuzz&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#putting-the-pieces-together-solving-fizzbuzz&quot;&gt;Putting the pieces together: solving FizzBuzz&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With our two new skills –
creating (imperfect) infinite arrays
and mapping over multiple arrays –
we are ready to tackle the fearsomely challenging puzzle of FizzBuzz.&lt;/p&gt;
&lt;h3 id=&quot;step-1-rules-of-fizzbuzz-as-arrays&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-1-rules-of-fizzbuzz-as-arrays&quot;&gt;Step 1: rules of FizzBuzz as arrays&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let's translate the &lt;a href=&quot;#rules-of-fizzbuzz&quot; class=&quot;link link-anchor&quot;&gt;rules of FizzBuzz&lt;/a&gt; to arrays (if that makes sense).
Let's also focus only on the first ten items of the FizzBuzz sequence for now.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Every 3rd item is 'Fizz'&amp;quot;&lt;/em&gt; means that
every 3rd item of an array is &lt;code&gt;'Fizz'&lt;/code&gt;.
Other items are irrelevant,
so they can be nulls:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Every 5th item is 'Buzz'&amp;quot;&lt;/em&gt; works similarly:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Every 15th item is 'FizzBuzz'&amp;quot;&lt;/em&gt; can be ignored for now
because the rule doesn't apply to a sequence of just ten items.
But it would work similarly to the two previous rules/arrays.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Other items are numbers&amp;quot;&lt;/em&gt; is simply an array of numbers starting from 1:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's see how they look when put into the &lt;code&gt;multimap&lt;/code&gt; function:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&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;args&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token 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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&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;// Console loggings:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [null,     null,  1]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [null,     null,  2]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ['Fizz',   null,  3]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [null,     null,  4]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [null,   'Buzz',  5]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ['Fizz',   null,  6]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [null,     null,  7]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [null,     null,  8]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ['Fizz',   null,  9]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [null,   'Buzz', 10]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Return value:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   [undefined × 10]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hmm, what if we take the first non-null item from each set of items?&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&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; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token 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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1,    2, 'Fizz',    4, 'Buzz', 'Fizz',    7,    8, 'Fizz', 'Buzz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hey, FizzBuzz! 😎
(Every 15th item will be handled soon.)&lt;/p&gt;
&lt;h3 id=&quot;step-2-truthy-vs-falsy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-2-truthy-vs-falsy&quot;&gt;Step 2: truthy vs falsy&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The arrays contain only strings, numbers and nulls.
Strings and numbers are &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Truthy&quot; class=&quot;link link-external&quot;&gt;truthy values&lt;/a&gt;,
and nulls are &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Falsy&quot; class=&quot;link link-external&quot;&gt;falsy values&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instead of taking the first non-null item,
the first truthy item can be taken,
and the result will be the same.
This simplifies the callback function:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&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; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token 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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1,    2, 'Fizz',    4, 'Buzz', 'Fizz',    7,    8, 'Fizz', 'Buzz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-cycling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-3-cycling&quot;&gt;Step 3: cycling 🚴‍♂️&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first two arrays are repeating,
so they can be simplified with the new &lt;code&gt;cycle&lt;/code&gt; function:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&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; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-4-range-function&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-4-range-function&quot;&gt;Step 4: &lt;code&gt;range&lt;/code&gt; function&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The third array is lame
because it's a manually-created range of numbers.
Let's create a &lt;code&gt;range&lt;/code&gt; function:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;from&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; to&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;
  Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; to &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; from &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 punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; from&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [5, 6, 7, 8]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&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; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;range&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 number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-5-index-argument-and-filler-arrays&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-5-index-argument-and-filler-arrays&quot;&gt;Step 5: &lt;code&gt;index&lt;/code&gt; argument and filler arrays&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;range&lt;/code&gt; function is not actually even needed.&lt;/p&gt;
&lt;p&gt;The callback function passed to the &lt;code&gt;multimap&lt;/code&gt; function
accepts &lt;code&gt;index&lt;/code&gt; as its second argument.
Just like the callback function passed to
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Array.prototype.map&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By using the &lt;code&gt;index&lt;/code&gt; argument,
the third array (range of numbers) is not needed,
and thus the &lt;code&gt;range&lt;/code&gt; function is not needed.&lt;/p&gt;
&lt;p&gt;But the third array can't just be omitted
as all of the remaining arrays would be infinite:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; RangeError: Invalid array length&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember that the &lt;code&gt;multimap&lt;/code&gt; function continues going over the arrays
until any of them is exhausted.
In other words,
&lt;code&gt;multimap&lt;/code&gt; goes over the arrays &lt;em&gt;n&lt;/em&gt; times
where &lt;em&gt;n&lt;/em&gt; is the length of the shortest array.&lt;/p&gt;
&lt;p&gt;Thus, &lt;code&gt;multimap&lt;/code&gt; can be provided a &amp;quot;filler&amp;quot; array with a certain length.
Because the other arrays are infinite,
the filler array's length determines how many times &lt;code&gt;multimap&lt;/code&gt; goes over the arrays.&lt;/p&gt;
&lt;p&gt;We are not interested in the filler array's values,
so an array with ten empty slots is fine:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [empty × 10]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;range&lt;/code&gt; function might be clearer,
but I'm going to continue using the filler array,
because filler arrays will be useful in the next steps.&lt;/p&gt;
&lt;h3 id=&quot;step-6-left-padded-arrays&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-6-left-padded-arrays&quot;&gt;Step 6: left-padded arrays&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first two arrays are mostly fillers too.
A more concise way of creating them
is to create filler arrays
and concatenating them with the last non-filler value:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before:&lt;/span&gt;
&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After:&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [empty × 2, 'Fizz']&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [empty × 4, 'Buzz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kinda like left-padding arrays...
Someone quickly publish &lt;code&gt;left-pad-array&lt;/code&gt; on npm!&lt;/p&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-7-the-remaining-rule&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-7-the-remaining-rule&quot;&gt;Step 7: the remaining rule&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The code works so far with Fizzes and Buzzes,
but not with FizzBuzzes.
Every 15th item is &amp;quot;Fizz&amp;quot; instead of &amp;quot;FizzBuzz&amp;quot;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    2,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    4,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    7,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    8,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    11,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    13,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    14,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz', // :( Should be 'FizzBuzz'&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An easy fix is to use another array
based on the remaining rule (&lt;em&gt;&amp;quot;every 15th item is 'FizzBuzz'&amp;quot;&lt;/em&gt;):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&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;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'FizzBuzz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    2,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    4,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    7,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    8,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    11,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    13,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    14,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'FizzBuzz', // :) Correct&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the new array is not actually necessary
because Fizz + Buzz = FizzBuzz:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;''&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; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [1,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    2,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    4,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    7,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    8,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Buzz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    11,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'Fizz',&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    13,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    14,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    'FizzBuzz', // Still correct&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;finished-result-playground&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#finished-result-playground&quot;&gt;Finished result + playground&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cycle&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&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;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; prop&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'length'&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 number&quot;&gt;Infinity&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&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;^\d+$&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&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;return&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;multimap&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;arrays&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; arrayLengths &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arrays&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&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; array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; smallestArrayLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&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;arrayLengths&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; smallestArrayLength &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arrays&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&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; array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&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 function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;from&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; to&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;
  Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; to &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; from &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 punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; from&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Variation 1:&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&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; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&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;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'FizzBuzz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;range&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 number&quot;&gt;15&lt;/span&gt;&lt;span class=&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;// Variation 2:&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;''&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; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are a lot more variations to discover.
For example, these two are nice:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;multimap&lt;/span&gt;&lt;span class=&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;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;fizz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buzz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;fizz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buzz&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;''&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; number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&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;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&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;range&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 number&quot;&gt;15&lt;/span&gt;&lt;span class=&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;multimap&lt;/span&gt;&lt;span class=&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;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; word &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cycle&lt;/span&gt;&lt;span class=&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;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Buzz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Fizz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'FizzBuzz'&lt;/span&gt;&lt;span class=&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;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBGADGgNCAZhBAzsgNqgB2AhmIkiAHQBWR2AxgPZkAu8XyIA9PwAEABVgUAngHMATmwCuZKEJxsZQgDogAYhABeegELyDQiGSEApCgDcKAZRYyIAB05CA7hE4ALM2Twyb3ghChkZSQJQpSEweVhOCDAKFxdzKS0hACMJIQBZCkSKKIBpczJFHjoNMkEhe3gQn05OFwIkQTBOAgBrMjI6PH4s2DYpfjwDLJM9AFpzWYZbYqdXTlmvXwV1mXhk8yh4GVmwNih4tlm2FyPCtX4amvYyAncWCRYEIQBeIQAKMIRCQASh+AD4hGR4B5RHIAB4SAHhSSYITAGpCIRSeCcP6cMLYziolxyFyg9EWTFmHD-EnXH7fX4AcgQZCkviZoN2nHkMgsAEkAuZvBIMVSIDS-vwAHoaDRQADUABJ+HRuK8-nSXGq2PZOM42X9gcahNzeRZ8TJCcQtUIAKRCS2Euis9k+AC6YsxZr5joJOJtpM9lIAvpgaiHgY8yM9XrF4olki4fv8cGRUXRM4DIqDvhCKZjY+5sxIADI8N1RX4lgh0JN-JFA3MQksuiu+KOUotCAjJWCETgAQWRZfbfl+BV8dfMf0zdBL5bZvgInbFPosw6BgzkYD+wCErt8SB7fYHm8ki7dQkjdZSDYA+qiIM20V6hN3gmAq6ER7X643JBfEtiAgd1OypU0cXNFQyD+T8CCfcDr07ENo27CI2RCX4-hwHdUU4NhmzFc8JG3Nhd33Q8fGPAihFmFQdyEBUhBQa9UT+R8zBfCAmIY8jV1qYQ9XgZMUBqBB3F2AgExTOIEiSO8xSRKQV3BH8VMGA4GzhF84SEABCRlIXiWBgXDSliAqftUSs2BUSZXQDCZGyTNRTFbPsxy9Gc4zrN8uyhAc-RvLc-z3XMzFLNc-zQo8mLAuMJzYuiuK4vc6KmUS7zws0CyqRQUKhAAJkKzEAGZCoAFlKoQAFYaoANkKgB2QqAA4aoATlK9Bg07OpBSEbQEC-VEAAMXCNMaUzG2M2AQF0xim-5pncCblooWACDYSCeT5KJfBCPAZDjAlUXYebO0mplhNEpAfKkhMBLqW7ipqR6ElkhMFMmpSCVUvN1NrQIoD+Qw2Hm+AKDIMyxSivy4qCpL4vSvykZC+LEa8nzUdgcK4dS6LcZctGspxzGUqJ+LMpmJkcrh-LCpKiDyqqmr6pZoQmog1qII6znupZ3qaiuv4bu4ZMivu1EPs4Z6hIloQyve+BpM+345MTRTKWUgGWytYGtPByHodhrsPgQP54YCrHgrps3Cwt+ArcJhHKdJ2mwIioRiAK4rUQqoRqrq1Fud5-nBeFmGamu16yulyC1bl6MXsVyqVaTr75PrP6DaAg3NKUMGIYQU3vfeT5netkmAvR+3y6dl33Zt5v7LJr212h7E-j99BO1F8WRKDhPZfl+pFdqjOZI176c51-7ELU-7C9B43S5hoQAB9N7MXiCrFCvLer6nsY783K6bt2r5bj2nLPzESJ7tB+5jsXXtqkfVaelOFaHhqp-VvGbO2tMS60XoDZeINi4mw3tvXezF97n0to-IqwI6DPBYIUMW2NjQNwvo-SqaCMFYJpk5XBxERxPxfmQWOisGqfyTmPV6vM7DOEKBADgLEAHuBnsA3688DbgP1hpKBa8oawJ3jxBBeDkGUJQIQ9BHBMG4nRmTchSDnYoKIUokhOCHbvkbgQ7RMYSFqP0Y-Mqz8Rav0HsmZqDDv5kBqKnIeLCwgQHYZwoq3Cs5a34aAheXEl4FwYGwGcTJORb0kXvGRmjKGoMUSYlRejYl-CMYk5RYszHewsVY6ONC36K3sQ9L+CQx6DjIGwQ66hWEeMSBwHxvC-F-CUsQSYehUTTAMC5MAWQjhgTUm04KnSZjukYGE2CETQRwIqL0o4qTj62zvvow+VdXY3w2W3T2+iMLdz9pY6h11wYVHaIFGWpTk5OMEkICpygJA4miFUnwRxGlAOaa0jwagoA5WfGpT5MhlBwKkSxBZ6zPJ2xrls5GddIUnwhQlWmsKYUUzRl5du5jKEHOsQUzKHB5CnJKYwkArByJpAQDIZAtkQzhRAJQagfB2ldL0EIFw4hpByEUFAEAIYgA&quot; class=&quot;link link-external&quot;&gt;Play around with the code on flems.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What kind of cool variations can you come up with?
Send me an email! 😎
(Address on the &lt;a href=&quot;/&quot; class=&quot;link&quot;&gt;home page&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#acknowledgements&quot;&gt;Acknowledgements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The approach and code in this blog post
were like 90% inspired by
the &lt;a href=&quot;https://www.youtube.com/watch?v=hSqpJpowazg&quot; class=&quot;link link-external&quot;&gt;YouTube video &lt;em&gt;FizzBuzz in Clojure with &amp;amp; without modulus/remainder/rest&lt;/em&gt; by Fred Overflow&lt;/a&gt;
(cool name!).&lt;/p&gt;
&lt;p&gt;I wanted to call this blog post
&amp;quot;FizzBuzz in JS without the remainder operator,&amp;quot;
but I couldn't
as I had to use the operator in the &lt;code&gt;cycle&lt;/code&gt; function.
&lt;span class=&quot;whitespace-no-wrap&quot;&gt;¯\(ツ)/¯&lt;/span&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/memoized-fibonacci-function-in-1-line-of-javascript/</id><title>Memoized Fibonacci function in 1 line of JavaScript</title><link href="https://mtsknn.fi/blog/memoized-fibonacci-function-in-1-line-of-javascript/" /><published>2021-08-05T12:00:00+03:00</published><updated>2021-08-05T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;Using recursion,
logical OR assignment operator (&lt;code&gt;||=&lt;/code&gt;),
BigInts
and more!&lt;/p&gt;
&lt;h2 id=&quot;whats-fibonacci&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-fibonacci&quot;&gt;What's Fibonacci?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From &lt;a href=&quot;https://en.wikipedia.org/w/index.php?title=Fibonacci_number&amp;amp;oldid=1035985207&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Fibonacci number&lt;/em&gt; on Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In mathematics,
the &lt;strong&gt;Fibonacci numbers&lt;/strong&gt;,
commonly denoted &lt;em&gt;F&lt;sub&gt;n&lt;/sub&gt;&lt;/em&gt;,
form a sequence,
called the &lt;strong&gt;Fibonacci sequence&lt;/strong&gt;,
such that each number is the sum of the two preceding ones,
starting from 0 and 1.
That is,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;F&lt;/em&gt;&lt;sub&gt;0&lt;/sub&gt; = 0,&lt;br&gt;
&lt;em&gt;F&lt;/em&gt;&lt;sub&gt;1&lt;/sub&gt; = 1,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;F&lt;sub&gt;n&lt;/sub&gt;&lt;/em&gt; = &lt;em&gt;F&lt;sub&gt;n-1&lt;/sub&gt;&lt;/em&gt; + &lt;em&gt;F&lt;sub&gt;n-2&lt;/sub&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;for &lt;em&gt;n &amp;gt; 1&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The sequence starts:&lt;/p&gt;
&lt;p&gt;0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;whats-memoization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-memoization&quot;&gt;What's memoization?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From &lt;a href=&quot;https://en.wikipedia.org/w/index.php?title=Memoization&amp;amp;oldid=1034309521&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Memoization&lt;/em&gt; on Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computing,
&lt;strong&gt;memoization&lt;/strong&gt; or &lt;strong&gt;memoisation&lt;/strong&gt; is an optimization technique
used primarily to speed up computer programs
by storing the results of expensive function calls
and returning the cached result
when the same inputs occur again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;step-1-recursive-function-without-memoization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-1-recursive-function-without-memoization&quot;&gt;Step 1: Recursive function without memoization&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Negative inputs are returned as-is,
and non-number inputs may break the function.
This is addressed in the &lt;a href=&quot;#bonus-3-input-validation-and-typescript-types&quot; class=&quot;link link-anchor&quot;&gt;3rd bonus section&lt;/a&gt;;
for now,
let's just live with it.&lt;/p&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fib&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 comment&quot;&gt;//=&gt; 0&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&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 comment&quot;&gt;//=&gt; 1&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&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 comment&quot;&gt;//=&gt; 1&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 2&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 3&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 5&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 8&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 13&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 21&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6_765&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 39_088_169&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~450ms on my machine 😬&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Demonstration of the lack of memoization:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; log &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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;
  log&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 55&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;log&lt;span class=&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;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; times&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    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;fib(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;n&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;) was called &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;times&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; times&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 comment&quot;&gt;//=&gt; fib(10) was called 1 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(9) was called 1 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(8) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(7) was called 3 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(6) was called 5 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(5) was called 8 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(4) was called 13 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(3) was called 21 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(2) was called 34 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(1) was called 55 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(0) was called 34 times&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's funny that those numbers –
how many times &lt;code&gt;fib(n)&lt;/code&gt; was called –
follow the Fibonacci sequence!
(Excluding the last one;
looks like the numbers could continue decrementing at the same rate?
Interesting.)&lt;/p&gt;
&lt;p&gt;No wonder calculating &lt;code&gt;fib(38)&lt;/code&gt; takes half a second.
&lt;code&gt;fib(1)&lt;/code&gt; gets called 39,088,169 times!&lt;/p&gt;
&lt;h2 id=&quot;step-2-memoization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-2-memoization&quot;&gt;Step 2: Memoization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Diff:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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 prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;cache&lt;/code&gt; is a &amp;quot;global&amp;quot; object for now.
We'll change it later.&lt;/p&gt;
&lt;p&gt;Performance is much better now:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 39_088_169&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; Less than 1ms on my machine 😎&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Demonstration of the presence of memoization:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 keyword&quot;&gt;const&lt;/span&gt; log &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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;
  log&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; log&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;log&lt;span class=&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;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; times&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    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;fib(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;n&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;) was called &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;times&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; times&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 comment&quot;&gt;//=&gt; fib(10) was called 1 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(9) was called 1 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(8) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(7) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(6) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(5) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(4) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(3) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(2) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(1) was called 2 times&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; fib(0) was called 1 times&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-3-golf&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-3-golf&quot;&gt;Step 3: Golf ⛳&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Code golfing = striving for the shortest possible source code.&lt;/p&gt;
&lt;h3 id=&quot;step-31-logical-or-assignment-operator-oror&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-31-logical-or-assignment-operator-oror&quot;&gt;Step 3.1: Logical OR assignment operator (&lt;code&gt;||=&lt;/code&gt;)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment&quot; class=&quot;link link-external&quot;&gt;logical OR assignment operator&lt;/a&gt;
was introduced in the ECMAScript 2021 spec&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;
and is perfect for our case.&lt;/p&gt;
&lt;p&gt;Diff:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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 prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-32-return-value-of-the-assignment-operator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-32-return-value-of-the-assignment-operator&quot;&gt;Step 3.2: Return value of the assignment operator&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In JavaScript,
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#return_value_and_chaining&quot; class=&quot;link link-external&quot;&gt;assignments have return values&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Like most expressions,
assignments like &lt;code&gt;x = y&lt;/code&gt; have a return value.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;That means that &lt;code&gt;(x = y)&lt;/code&gt; returns &lt;code&gt;y&lt;/code&gt;,
&lt;code&gt;(x += y)&lt;/code&gt; returns the resulting sum &lt;code&gt;x + y&lt;/code&gt;,
&lt;code&gt;(x **= y)&lt;/code&gt; returns the resulting power &lt;code&gt;x ** y&lt;/code&gt;,
and so on.&lt;/p&gt;
&lt;p&gt;In the case of logical assignments,
&lt;code&gt;(x &amp;amp;&amp;amp;= y)&lt;/code&gt;, &lt;code&gt;(x ||= y)&lt;/code&gt;, and &lt;code&gt;(x ??= y)&lt;/code&gt;,
the return value is that of the logical operation without the assignment,
so &lt;code&gt;x &amp;amp;&amp;amp; y&lt;/code&gt;, &lt;code&gt;x || y&lt;/code&gt;, and &lt;code&gt;x ?? y&lt;/code&gt;,
respectively.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Diff:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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 prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&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;cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The outermost parentheses in the return statement are added by Prettier,
but they are optional.&lt;/p&gt;
&lt;h3 id=&quot;step-33-ternary-operator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-33-ternary-operator&quot;&gt;Step 3.3: Ternary operator&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Diff:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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 prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
&lt;span class=&quot;token prefix deleted&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;cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-34-pass-cache-as-a-parameter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-34-pass-cache-as-a-parameter&quot;&gt;Step 3.4: Pass cache as a parameter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Diff:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &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 prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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 operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache &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&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 prefix inserted&quot;&gt;+&lt;/span&gt;  n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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; _cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache &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&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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; _cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yay,
we got rid of the &amp;quot;global&amp;quot; &lt;code&gt;cache&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;The downside of passing cache as a parameter
is that the cache is discarded afterwards.
This reduces performance if &lt;code&gt;fib()&lt;/code&gt; is called many times:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before (global cache):&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50_000&lt;/span&gt; &lt;span class=&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 operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1_000&lt;/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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ~5ms&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After (cache as parameter):&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50_000&lt;/span&gt; &lt;span class=&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 operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1_000&lt;/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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ~2,000ms&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay,
that's silly.
Who would call &lt;code&gt;fib(1_000)&lt;/code&gt; 50,000 times? 😅
But the point remains that the performance is worse.&lt;/p&gt;
&lt;p&gt;The new function parameter is prefixed with an underscore
to denote that it's a &amp;quot;private&amp;quot; parameter
not meant to be used by the user of the function.&lt;/p&gt;
&lt;p&gt;Though it &lt;em&gt;can&lt;/em&gt; be used,
and doing so will fix the performance problem:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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; cache &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;
Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50_000&lt;/span&gt; &lt;span class=&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 operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1_000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ~5ms&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think an optional cache parameter
is the best of both worlds:
you can just call &lt;code&gt;fib(n)&lt;/code&gt; and not have to care about creating a cache object,
but you can also easily create a persistent cache if you need to.&lt;/p&gt;
&lt;h3 id=&quot;step-35-obfuscate-the-code-to-fit-on-a-single-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#step-35-obfuscate-the-code-to-fit-on-a-single-line&quot;&gt;Step 3.5: Obfuscate the code to fit on a single line 😅&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We are almost there!
The code from the previous step could already be placed on a single line,
but I want to let Prettier format my code.&lt;/p&gt;
&lt;p&gt;Renaming &lt;code&gt;_cache&lt;/code&gt; to &lt;code&gt;c&lt;/code&gt; &lt;em&gt;almost&lt;/em&gt; makes the code fit on a single line:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c &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&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &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; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's only 1 character too long!&lt;/p&gt;
&lt;p&gt;We can further reduce the code's length
by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Decrement&quot; class=&quot;link link-external&quot;&gt;decrement operator&lt;/a&gt;
instead of &lt;code&gt;n - 1&lt;/code&gt; and &lt;code&gt;n - 2&lt;/code&gt;.
Note that we have to use it in prefix position:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c &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&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;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&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;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&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;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the code fits on a single line! 💪&lt;/p&gt;
&lt;p&gt;We could golf more by
changing &lt;code&gt;const&lt;/code&gt; to &lt;code&gt;let&lt;/code&gt;,
renaming &lt;code&gt;fib&lt;/code&gt; to &lt;code&gt;f&lt;/code&gt;,
and removing unnecessary spaces and parentheses:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;c&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&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;n&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;n&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;f&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;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;f&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;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But that would be silly.&lt;/p&gt;
&lt;p&gt;In fact,
this whole step 3.5 is kind of silly.
I would prefer the code from &lt;a href=&quot;#step-34-pass-cache-as-a-parameter&quot; class=&quot;link link-anchor&quot;&gt;step 3.4&lt;/a&gt;.
It spans on two lines,
but at least it's readable.&lt;/p&gt;
&lt;h2 id=&quot;bonuses&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonuses&quot;&gt;Bonuses&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are bonuses,
so we don't necessarily have to aim for the line length of one. 😜&lt;/p&gt;
&lt;h3 id=&quot;bonus-1-arbitrarily-large-integers-with-bigints&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-1-arbitrarily-large-integers-with-bigints&quot;&gt;Bonus 1: Arbitrarily large integers with BigInts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Number.MAX_SAFE_INTEGER&lt;/code&gt; constant&lt;/a&gt;
represents the maximum safe integer in JavaScript (&lt;code&gt;2^53 - 1&lt;/code&gt;).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Safe in this context refers to
the ability to represent integers exactly and to correctly compare them.
For example,
&lt;code&gt;Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2&lt;/code&gt; will evaluate to true,
which is mathematically incorrect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;2^53 - 1&lt;/code&gt; sounds large,
but it's exceeded quite quickly when calculating Fibonacci numbers:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;78&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                 &lt;span class=&quot;token comment&quot;&gt;//=&gt;  8_944_394_323_791_464&lt;/span&gt;
Number&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_SAFE_INTEGER&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt;  9_007_199_254_740_991&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;79&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                 &lt;span class=&quot;token comment&quot;&gt;//=&gt; 14_472_334_024_676_220 (incorrect!)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://duckduckgo.com/?q=fibonacci+79&amp;amp;ia=answer&quot; class=&quot;link link-external&quot;&gt;A quick Duck search&lt;/a&gt;
shows that our result for &lt;code&gt;fib(79)&lt;/code&gt; is incorrect;
the correct value is our result plus one.&lt;/p&gt;
&lt;p&gt;We should instead use
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt&quot; class=&quot;link link-external&quot;&gt;BigInt values&lt;/a&gt;,
introduced in the ECMAScript 2020 spec&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.
BigInts can be used for arbitrarily large integers.&lt;/p&gt;
&lt;p&gt;BigInts can be created in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;by appending &lt;code&gt;n&lt;/code&gt; to the end of an integer literal (&lt;code&gt;100n&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;by calling the &lt;code&gt;BigInt()&lt;/code&gt; constructor without the &lt;code&gt;new&lt;/code&gt; operator
(&lt;code&gt;BigInt(100)&lt;/code&gt;, &lt;code&gt;BigInt(100n)&lt;/code&gt; or &lt;code&gt;BigInt('100')&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BigInts can't be mixed with regular numbers,
so we have to change &lt;code&gt;n - 1&lt;/code&gt; to &lt;code&gt;n - 1n&lt;/code&gt;
and &lt;code&gt;n - 2&lt;/code&gt; to &lt;code&gt;n - 2n&lt;/code&gt;.
However,
BigInts &lt;em&gt;can&lt;/em&gt; be compared with regular numbers,
so we don't have to change &lt;code&gt;n &amp;lt; 2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After introducing BigInts to the code from &lt;a href=&quot;#step-34-pass-cache-as-a-parameter&quot; class=&quot;link link-anchor&quot;&gt;step 3.4&lt;/a&gt;,
the code looks like this:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache &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&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&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;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;78n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                &lt;span class=&quot;token comment&quot;&gt;//=&gt;  8_472_334_024_676_464n&lt;/span&gt;
Number&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_SAFE_INTEGER&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt;  9_472_334_024_676_991&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;79n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                &lt;span class=&quot;token comment&quot;&gt;//=&gt; 14_472_334_024_676_221n (correct!)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1_000n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 43_466_557_686_937_472_334_024_676_675_472_334_024_676_660_472_334_024_676_481_472_334_024_676_417_472_334_024_676_879_472_334_024_676_295_472_334_024_676_634_472_334_024_676_239_472_334_024_676_642_472_334_024_676_187_472_334_024_676_928_472_334_024_676_137_472_334_024_676_875n 😅&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Performance seems about the same.
The above code runs in less than 2ms on my machine.&lt;/p&gt;
&lt;p&gt;Note that our function has to be called with a BigInt.
Calling it with a regular number will throw a TypeError:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Chrome: &quot;Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Firefox: &quot;Uncaught TypeError: can't convert BigInt to number&quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We'll change this in the &lt;a href=&quot;#bonus-3-input-validation-and-typescript-types&quot; class=&quot;link link-anchor&quot;&gt;3rd bonus section&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;bonus-2-avoiding-stack-overflows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-2-avoiding-stack-overflows&quot;&gt;Bonus 2: Avoiding stack overflows&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We can now support arbitrarily large integers,
except we can't
because too large inputs
cause stack overflow errors:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10_000n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Chrome: &quot;Uncaught RangeError: Maximum call stack size exceeded&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Firefox: No problem on my machine!&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100_000n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Chrome: &quot;Uncaught RangeError: Maximum call stack size exceeded&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Firefox: &quot;Uncaught InternalError: too much recursion&quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's what we can do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make our function &lt;code&gt;async&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Periodically pause our function with &lt;code&gt;await&lt;/code&gt;, Promises and timeouts,
so that the call stack can be periodically emptied.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like so; I put a log statement for demonstration
(notice also the non-highlighted &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; keywords):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache &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&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1_000n&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0n&lt;/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;&lt;span class=&quot;token string&quot;&gt;'Pausing at n ='&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&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;
  _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&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 function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&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; _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;await&lt;/code&gt; inside the second &lt;code&gt;if&lt;/code&gt; statement
pauses the function until the new Promise is resolved,
i.e. until &lt;code&gt;resolve()&lt;/code&gt; is called.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;setTimeout()&lt;/code&gt; puts the calling of &lt;code&gt;resolve()&lt;/code&gt;
to the end of the browser's task queue.
Tasks are processed only when the call stack is empty.
In other words,
our function resumes only after the call stack has been emptied,
so now we won't get stack overflow errors.&lt;/p&gt;
&lt;p&gt;If you are not following,
please read Jake Archibald's great article
&lt;a href=&quot;https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Tasks, microtasks, queues and schedules&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; 354_224_848_179_261_915_075n&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ~10ms&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5_000n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 5000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 4000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 3000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 2000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 1000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 1000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 2000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 3000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Pausing at n = 4000n&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; (returns a big-ass number)&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ~1,200ms&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two problems though:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The function is now very slow.&lt;/li&gt;
&lt;li&gt;The page becomes janky with large inputs (e.g. &lt;code&gt;fib(5_000n)&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jankiness could be reduced by pausing more often
(e.g. &lt;code&gt;if (n % 100n === 0n)&lt;/code&gt;),
but it would make the function even slower
(more pausing means more waiting).&lt;/p&gt;
&lt;p&gt;At this point it would anyway be better to use a non-recursive function
(see the &lt;a href=&quot;#bonus-4-non-recursive-non-memoized-function&quot; class=&quot;link link-anchor&quot;&gt;4th bonus section&lt;/a&gt;).
It would be much faster
and would have no stack overflow problems.
Move it to a Web Worker
and the page wouldn't become janky even with enormous inputs.&lt;/p&gt;
&lt;h4&gt;Sidetrack: &lt;code&gt;await new Promise(setTimeout)&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;If we were code golfing,
we could shorten our pausing code like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&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;// After&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;setTimeout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The shortened code works
because the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise&quot; class=&quot;link link-external&quot;&gt;Promise constructor&lt;/a&gt;
takes one function parameter (&lt;code&gt;executor&lt;/code&gt;),
which in turn takes two function parameters
(&lt;code&gt;resolutionFunc&lt;/code&gt; and &lt;code&gt;rejectionFunc&lt;/code&gt;).
So, &lt;code&gt;new Promise(setTimeout)&lt;/code&gt; expands to:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolutionFunc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rejectionFunc&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolutionFunc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rejectionFunc&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;setTimeout&lt;/code&gt;'s second parameter (&lt;code&gt;delay&lt;/code&gt; in milliseconds)
gets coerced into a number,
so basically &lt;code&gt;Number(rejectionFunc)&lt;/code&gt;&lt;sup&gt;&lt;a aria-label=&quot;footnote 3&quot; class=&quot;link&quot; href=&quot;#fn-3&quot; id=&quot;fnref-3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;,
which is &lt;code&gt;NaN&lt;/code&gt;,
which is the same as omitting the second parameter.&lt;/p&gt;
&lt;p&gt;Of course,
the shorter code shouldn't be generally used
because it's too cryptic.&lt;/p&gt;
&lt;h3 id=&quot;bonus-3-input-validation-and-typescript-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-3-input-validation-and-typescript-types&quot;&gt;Bonus 3: Input validation and TypeScript types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned in &lt;a href=&quot;#step-1-recursive-function-without-memoization&quot; class=&quot;link link-anchor&quot;&gt;step 1&lt;/a&gt;,
negative inputs are returned as-is,
and non-number inputs may break the function.
Let's add input validation:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache &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&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'n must be non-negative'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; n
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1_000n&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0n&lt;/span&gt;&lt;span class=&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;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&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;
  _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&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 function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&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; _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&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 comment&quot;&gt;//=&gt;  Error: n must be non-negative&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&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;1n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; Error: n must be non-negative&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It would be nice to accept regular numbers as well.
It would be no &amp;quot;validation,&amp;quot;
but let's add that:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache &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&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'n must be non-negative'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'bigint'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1_000n&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0n&lt;/span&gt;&lt;span class=&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;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&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;
  _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&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 function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&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; _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt;  55n&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 55n&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that our function is ready,
let's add TypeScript types:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fib &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  n&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; bigint&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  _cache&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;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&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; bigint &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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;bigint&lt;span class=&quot;token operator&quot;&gt;&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'n must be non-negative'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'bigint'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1_000n&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0n&lt;/span&gt;&lt;span class=&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;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&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;resolve&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 function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&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;
  _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cache&lt;span class=&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; _cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eh, quite ugly and way more than 1 line (14). 😅&lt;/p&gt;
&lt;p&gt;Note that instead of &lt;code&gt;_cache[n]&lt;/code&gt;
I had to explicitly use &lt;code&gt;_cache[n.toString()]&lt;/code&gt;.
A reason for this can be found in the
&lt;a href=&quot;https://basarat.gitbook.io/typescript/type-system/index-signatures#typescript-index-signature&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;TypeScript Index Signature&lt;/em&gt; section of the &lt;em&gt;TypeScript Deep Dive&lt;/em&gt; book&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;bonus-4-non-recursive-non-memoized-function&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-4-non-recursive-non-memoized-function&quot;&gt;Bonus 4: Non-recursive non-memoized function&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I wanted to see how much faster a non-recursive function would be:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fib&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&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;let&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0n&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0n&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&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;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&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;b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; c
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 55n (correct)&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5_000&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~3ms&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&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;fib&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100_000&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;timeEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; ~90ms&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much faster,
so this whole blog post was a bit silly in the end. 🙈&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;See
&lt;a href=&quot;https://github.com/tc39/proposals/blob/master/finished-proposals.md&quot; class=&quot;link link-external&quot;&gt;list of finished ECMAScript proposals on GitHub&lt;/a&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;See previous footnote. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;&lt;p&gt;See Dr. Axel Rauschmayer's article
&lt;a href=&quot;https://2ality.com/2019/10/type-coercion.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Type coercion in JavaScript&lt;/em&gt;&lt;/a&gt;
for details. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/11ty-vs-eleventy/</id><title>11ty vs Eleventy</title><link href="https://mtsknn.fi/blog/11ty-vs-eleventy/" /><published>2021-08-01T12:00:00+03:00</published><updated>2021-08-01T12:00:00+03:00</updated><category term="Eleventy"></category><content type="html">&lt;p&gt;The two names are often used interchangeably,
but there's a slight difference:
11ty is the organization,
Eleventy is the static site generator.&lt;/p&gt;
&lt;p&gt;I used to use the name &amp;quot;11ty&amp;quot;
when talking about
&lt;a href=&quot;https://www.11ty.dev/&quot; class=&quot;link link-external&quot;&gt;Eleventy, the static site generator&lt;/a&gt;.
Apparently that's slightly wrong;
from &lt;a href=&quot;https://github.com/11ty/eleventy/issues/921#issuecomment-879070567&quot; class=&quot;link link-external&quot;&gt;a GitHub comment by Zach Leatherman (the author of Eleventy)&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;11ty is the org and eleventy is the software.
I know that's confusing.
In retrospect it may have been nicer to use &lt;code&gt;11ty/11ty&lt;/code&gt; but I didn't 😅.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There you have it.
From now on
I'm going to use the name &amp;quot;Eleventy&amp;quot;
when talking about the static site generator.
A bit shame,
since &amp;quot;11ty&amp;quot; looks better.&lt;/p&gt;
&lt;p&gt;When to use the name &amp;quot;11ty&amp;quot; then?
Dunno,
I rarely talk about the organization.&lt;/p&gt;
&lt;p&gt;By the way,
some extra confusion before you go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/&quot; class=&quot;link link-external&quot;&gt;Eleventy's website&lt;/a&gt;
is at 11ty.dev.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy/&quot; class=&quot;link link-external&quot;&gt;Eleventy's GitHub page&lt;/a&gt;
has a big &amp;quot;11ty&amp;quot; logo at the top.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/eleven_ty/&quot; class=&quot;link link-external&quot;&gt;Eleventy's Twitter account&lt;/a&gt;
has an &amp;quot;11ty&amp;quot; avatar.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-render-optimizely-content-recommendations-using-react/</id><title>How to render Optimizely Content Recommendations using React</title><link href="https://mtsknn.fi/blog/how-to-render-optimizely-content-recommendations-using-react/" /><published>2021-06-24T12:00:00+03:00</published><updated>2021-08-17T12:00:00+03:00</updated><category term="Episerver"></category><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;Also known as Episerver/Idio Content Recommendations.
The usual way of using a Mustache template
can be circumvented by using a JavaScript proxy.&lt;/p&gt;
&lt;h2 id=&quot;what-is-optimizely-content-recommendations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#what-is-optimizely-content-recommendations&quot;&gt;What is Optimizely Content Recommendations?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.episerver.com/products/capabilities/web-content-recommendations&quot; class=&quot;link link-external&quot;&gt;Episerver's marketing page describes Web Content Recommendations&lt;/a&gt;
like so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Serve each visitor the most relevant content automatically.
AI-powered recommendations
act upon the unique interests of each visitor in real-time
to help you deliver personalization with minimal manual effort.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://world.episerver.com/documentation/developer-guides/personalization/content-recommendations/&quot; class=&quot;link link-external&quot;&gt;Optimizely's developer docs describe Content Recommendations&lt;/a&gt;
maybe slightly more clearly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Optimizely Content Recommendations
automatically generates a personalized content feed for each visitor
based on the individual's site activity.&lt;/p&gt;
&lt;p&gt;Content Recommendations uses Natural Language Processing (NLP)
to understand the meaning of each piece of content at a granular level
and builds a real-time interest profile for each visitor
based on their interactions with the NLP-generated topics.
Content Recommendations uses this information to recommend
articles, blog posts, or other specified content sections
that are most relevant to the visitor's interest profile.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;
Personalized content recommendations
based on visitor tracking
and natural language processing of the content pages.&lt;/p&gt;
&lt;h3 id=&quot;optimizely-vs-episerver-vs-idio&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#optimizely-vs-episerver-vs-idio&quot;&gt;Optimizely vs Episerver vs Idio&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Optimizely Content Recommendations
have been previously called Episerver Content Recommendations,
and before that Idio Content Recommendations.
Some context:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.episerver.com/campaign/idio&quot; class=&quot;link link-external&quot;&gt;Episerver acquired a company called Idio in November 2019.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.episerver.com/campaign/optimizely&quot; class=&quot;link link-external&quot;&gt;Episerver acquired a company called Optimizely in October 2020&lt;/a&gt;
and now
&lt;a href=&quot;https://www.episerver.com/campaign/becoming-optimizely&quot; class=&quot;link link-external&quot;&gt;Episerver is rebranding itself as Optimizely&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;usual-implementation-mustache-template&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#usual-implementation-mustache-template&quot;&gt;Usual implementation: Mustache template&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On pages where you want to see intelligent content recommendations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;a href=&quot;https://mustache.github.io/mustache.5.html&quot; class=&quot;link link-external&quot;&gt;Mustache template&lt;/a&gt;
with the class &lt;code&gt;idio-recommendations&lt;/code&gt;.
Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;script&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;idio-recommendations&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;data-api-key&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;text/x-mustache&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 script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div &lt;span class=&quot;token keyword&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;recommendation&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;#content&lt;span class=&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;h2&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;a href&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{link_url}}&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;title&lt;span class=&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;a&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;h2&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;img alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{main_image_url}}&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&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;p&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;abstract&lt;span class=&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;p&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;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        Published on &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span &lt;span class=&quot;token keyword&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;date&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;published&lt;span class=&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;span&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;p&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 operator&quot;&gt;/&lt;/span&gt;content&lt;span class=&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;div&lt;span class=&quot;token operator&quot;&gt;&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;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Load &lt;code&gt;ip.js&lt;/code&gt; script (&amp;quot;Idio Personalization&amp;quot;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When the page is loaded,
the &lt;code&gt;ip.js&lt;/code&gt; script will
look for the Mustache template,
and if found,
load content recommendations via an Ajax request
and render the Mustache template with the loaded data.&lt;/p&gt;
&lt;p&gt;Quite straightforward.
If this works for you,
great!&lt;/p&gt;
&lt;h3 id=&quot;problems-when-using-with-react&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problems-when-using-with-react&quot;&gt;Problems when using with React&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Rendering a Mustache template to the page using React is not a problem.
Some other basic things are however difficult:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to format dates in the Mustache template?
They are rendered in the &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot; class=&quot;link link-external&quot;&gt;ISO 8601&lt;/a&gt; format by default
and I haven't found a way to customize that.&lt;/li&gt;
&lt;li&gt;How to handle links in the Mustache template
so that the links are handled like SPA (single page app) links?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I suspect that other basic things would also be difficult.&lt;/p&gt;
&lt;h2 id=&quot;naive-and-hacky-react-implementation-not-recommended&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#naive-and-hacky-react-implementation-not-recommended&quot;&gt;Naive and hacky React implementation (not recommended)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;I don't recommend this approach.&lt;/strong&gt;
Check the next section for a better approach.
I'm documenting this here
because this is what I tried first.&lt;/p&gt;
&lt;p&gt;Content Recommendations offers a way to run your own logic
after the Mustache template has been populated with data.&lt;/p&gt;
&lt;p&gt;After &lt;code&gt;ip.js&lt;/code&gt; has loaded the data via Ajax
and rendered the Mustache template,
it will look for a &lt;code&gt;window._ipc&lt;/code&gt; object
(apparently stands for &amp;quot;Idio Personalization Config&amp;quot;)
and call its &lt;code&gt;complete&lt;/code&gt; function (if it exists) with two arguments:
a reference to the DOM element containing the recommendations,
and a status code of the Ajax response.&lt;/p&gt;
&lt;p&gt;By utilizing the &lt;code&gt;window._ipc&lt;/code&gt; object,
it should be possible to
do these steps after the Mustache template has been rendered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Format dates inside the DOM element by mutating them.&lt;/li&gt;
&lt;li&gt;Attach click event listeners to the links inside the DOM element
for SPA-like navigation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Something like this (quick and dirty code):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ContentRecommendations&lt;/span&gt;&lt;span class=&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;useIdioPersonalizationConfig&lt;/span&gt;&lt;span class=&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 punctuation&quot;&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;script&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;className&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;idio-recommendations&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;data-api-key&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;text/x-mustache&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 plain-text&quot;&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;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useIdioPersonalizationConfig&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; links &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;

    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_ipc &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 function&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;element&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; statusCode&lt;/span&gt;&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;element &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; statusCode &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&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;

        element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.date'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;date&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;
          date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &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;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&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;toLocaleString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&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;

        links &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;link&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;
          link&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;'click'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleLinkClick&lt;span class=&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;return&lt;/span&gt; &lt;span class=&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;
      links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;link&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;
        link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'click'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleLinkClick&lt;span class=&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 punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how I have to remove the links' click event listeners
in the &lt;code&gt;useEffect&lt;/code&gt;'s cleanup function
to avoid memory leaks.&lt;/p&gt;
&lt;p&gt;Is this good?
Nah, it's very hacky.
I don't like to see this kind of code in a React project.&lt;/p&gt;
&lt;p&gt;If there are more things that you have to do like this –
things that you can't do with just the Mustache template –
the code becomes even uglier.&lt;/p&gt;
&lt;h2 id=&quot;better-albeit-still-hacky-react-implementation-recommended&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#better-albeit-still-hacky-react-implementation-recommended&quot;&gt;Better (albeit still hacky) React implementation (recommended)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It would be nice
if we could do the Ajax requests ourselves,
but that's not possible.
Plus in the end
I think it's best to leave the request logic to &lt;code&gt;ip.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It would be even better
if we could get the Ajax response's data directly
instead of letting &lt;code&gt;ip.js&lt;/code&gt; use it to render the Mustache template.
But that's not possible...
unless we use a certain hack. 🤪&lt;/p&gt;
&lt;h3 id=&quot;the-flow-of-things&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-flow-of-things&quot;&gt;The flow of things&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I did some digging,
and the flow goes like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;After the page has loaded,
&lt;code&gt;ip.js&lt;/code&gt; does some initializations like this:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio &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;
window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;token operator&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 comment&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;token operator&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 comment&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how &lt;code&gt;ip.js&lt;/code&gt; doesn't override the &lt;code&gt;window.idio&lt;/code&gt; object
if it already exists.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ip.js&lt;/code&gt; looks for Mustache templates
with the class &lt;code&gt;idio-recommendations&lt;/code&gt;.
(Actually, it looks for any &lt;code&gt;script&lt;/code&gt; elements
with that class.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If a template is found,
&lt;code&gt;ip.js&lt;/code&gt; does an Ajax request to get content recommendations for the user.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Ajax response contains JavaScript code like this:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;r0&lt;/span&gt;&lt;span class=&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;total_hits&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1234&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 comment&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;/* ... */&lt;/span&gt; &lt;span class=&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;// ...&lt;/span&gt;
  &lt;span class=&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;200&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I.e. the returned code calls &lt;code&gt;window.idio.r0&lt;/code&gt;
with the content recommendations data
and a status code of the Ajax response.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;window.idio.r0&lt;/code&gt; renders the Mustache template with the data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the page contains more than one Mustache template,
the first Ajax response calls &lt;code&gt;window.idio.r0&lt;/code&gt;,
the second one calls &lt;code&gt;window.idio.r1&lt;/code&gt;,
and so on.
So the &amp;quot;r&amp;quot; is apparently &amp;quot;render&amp;quot; or &amp;quot;result,&amp;quot;
and the number is a 0-based index.&lt;/p&gt;
&lt;h3 id=&quot;the-hack-proxying-windowidio&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-hack-proxying-windowidio&quot;&gt;The hack: proxying &lt;code&gt;window.idio&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So,
everything is fine to us
except the last step.
If only we could do something else
than let &lt;code&gt;ip.js&lt;/code&gt; render the Mustache template
when &lt;code&gt;window.idio.r0&lt;/code&gt; is called...&lt;/p&gt;
&lt;p&gt;Well, that's what
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot; class=&quot;link link-external&quot;&gt;JavaScript proxies&lt;/a&gt;
are for!
We can use one to make &lt;code&gt;window.idio.r0&lt;/code&gt; return something else
when it's accessed.&lt;/p&gt;
&lt;p&gt;As we saw earlier,
&lt;code&gt;ip.js&lt;/code&gt; doesn't override the &lt;code&gt;window.idio&lt;/code&gt; object
if it already exists.
So we can define it ourselves
before loading &lt;code&gt;ip.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio &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;Proxy&lt;/span&gt;&lt;span class=&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 function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; prop&lt;span class=&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; prop &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'r0'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; handleAjaxResponse &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Alternatively, if the page can contain more than one Mustache template:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&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;^r\d+$&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 function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&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; handleAjaxResponse &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// The `toString()` is needed because `prop` can be a Symbol,&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// and the `test()` method would otherwise throw:&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// &quot;Cannot convert a Symbol value to a string&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;
&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 function&quot;&gt;handleAjaxResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; statusCode&lt;/span&gt;&lt;span class=&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;// Do whatever with the data 🤘&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I'm setting &lt;code&gt;window.idio&lt;/code&gt; to a proxy object which:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Returns my own &lt;code&gt;handleAjaxResponse&lt;/code&gt; function when &lt;code&gt;window.idio.r0&lt;/code&gt; is accessed
(instead of returning what &lt;code&gt;window.idio.r0&lt;/code&gt; actually is).&lt;/li&gt;
&lt;li&gt;Otherwise makes &lt;code&gt;window.idio&lt;/code&gt; work normally.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words,
I can do whatever I like in &lt;code&gt;handleAjaxResponse&lt;/code&gt;.
Check the next section for an example what to do with the data.&lt;/p&gt;
&lt;p&gt;Heh, this is hacky and fragile,
but so is the Mustache + React combo.
At least now I don't have to have a mix of
Mustache, React and procedural DOM mutations.&lt;/p&gt;
&lt;p&gt;Goodbye Mustache!&lt;/p&gt;
&lt;h3 id=&quot;sample-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sample-code&quot;&gt;Sample code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I'll leave it as an exercise for you
to clean up and properly comment the code. 🙂&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ContentRecommendations&lt;/span&gt;&lt;span class=&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; recommendations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useContentRecommendations&lt;/span&gt;&lt;span class=&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 punctuation&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/*
        Content recommendations are loaded
        only if a Mustache template with this class is found on the page.
      */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;script&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;className&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;idio-recommendations&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;data-api-key&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;data-rpp&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;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Results per page&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;text/x-mustache&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 plain-text&quot;&gt;

      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;recommendations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Recommended content&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;ContentRecommendationsList&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;recommendations&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;recommendations&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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 plain-text&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ContentRecommendationsList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; recommendations &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;formatDate&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;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;date&lt;span class=&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;toLocaleString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en'&lt;/span&gt;&lt;span class=&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;dateStyle&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'medium'&lt;/span&gt; &lt;span class=&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; recommendations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;recommendation&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;recommendation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&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;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* Look ma, can use router links! */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;RouterLink&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;recommendation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;link_url&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;recommendation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;RouterLink&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 plain-text&quot;&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;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;recommendation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;main_image_url&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;recommendation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;abstract&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* Look ma, date formatting! */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        Published on &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;formatDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recommendation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;published&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&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;/**
 * Get content recommendations loaded by `ip.js` (&quot;Idio Personalization&quot;).
 *
 * Hacky! Read on for details.
 *
 * What `ip.js` does:
 *
 * 1. Look for a Mustache template with the class `idio-recommendations`.
 * 2. If found, load content recommendations data via Ajax.
 * 3. Call `window.idio.r0(data, statusCode)`
 *    with the Ajax response data and status code.
 *
 * Normally `window.idio.r0` compiles the Mustache template,
 * but `useIdioProxy` intercepts calls to `window.idio.r0`
 * so that we can handle the data ourselves.
 *
 * More detailed description and original code at
 * https://mtsknn.fi/blog/how-to-render-optimizely-content-recommendations-using-react/
 *
 * @returns {object[]}
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useContentRecommendations&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;recommendations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setRecommendations&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&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;useIdioProxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;setRecommendations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useIdioPersonalizationScript&lt;/span&gt;&lt;span class=&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; recommendations
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * Create a proxy object for `window.idio`
 * to intercept calls to `window.idio.r0`.
 *
 * Must be run before loading `ip.js`
 * to ensure that the proxy is in place
 * when loading the content recommendations data.
 *
 * `ip.js` sets `window.idio = window.idio || {}`,
 * so our proxy isn't overridden.
 *
 * @param {React.Dispatch&amp;lt;React.SetStateAction&amp;lt;object[]&gt;&gt;} setRecommendations
 * React state setter.
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useIdioProxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;setRecommendations&lt;/span&gt;&lt;span class=&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; handleAjaxResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useCallback&lt;/span&gt;&lt;span class=&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;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; statusCode&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;statusCode &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&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;// Show error or do logging or whatever&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;setRecommendations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&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;setRecommendations&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&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;
    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio &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;Proxy&lt;/span&gt;&lt;span class=&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 function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property&lt;span class=&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; property &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'r0'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; handleAjaxResponse &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;property&lt;span class=&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;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;idio
  &lt;span class=&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;handleAjaxResponse&lt;span class=&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;/**
 * Load `ip.js` (&quot;Idio Personalization&quot;)
 * which loads Optimizely Content Recommendations.
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useIdioPersonalizationScript&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; script &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'script'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;async &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'https://.../ip.js'&lt;/span&gt;

    document
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'script'&lt;/span&gt;&lt;span class=&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;insertAdjacentElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'beforebegin'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; script&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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-trigger-daily-netlify-builds-using-github-actions/</id><title>How to trigger daily Netlify builds using GitHub Actions</title><link href="https://mtsknn.fi/blog/how-to-trigger-daily-netlify-builds-using-github-actions/" /><published>2021-06-22T12:00:00+03:00</published><updated>2021-06-22T12:00:00+03:00</updated><category term="Eleventy"></category><category term="Git"></category><category term="Netlify"></category><content type="html">&lt;p&gt;Or any other automatic periodic builds.
I'm using daily builds to
automatically publish scheduled blog posts
on my Eleventy site.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.netlify.com/configure-builds/build-hooks/&quot; class=&quot;link link-external&quot;&gt;Create a build hook on Netlify.&lt;/a&gt;
Name it e.g. &amp;quot;Daily build from GitHub Actions.&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;quot;Build hooks are URLs you can use to trigger new builds and deploys.&amp;quot;
To trigger a build,
you can send a &lt;code&gt;POST&lt;/code&gt; request to the URL.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository&quot; class=&quot;link link-external&quot;&gt;Create an encrypted secret for your GitHub repository.&lt;/a&gt;
Name it e.g. &lt;code&gt;NETLIFY_DAILY_BUILD_HOOK&lt;/code&gt;
and use the URL from step 1 as the value.&lt;/p&gt;
&lt;p&gt;We are storing the URL as a secret
because otherwise someone could spam the URL
and rob you from your Netlify account's build minutes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a cron schedule expression using e.g. &lt;a href=&quot;https://crontab.guru/&quot; class=&quot;link link-external&quot;&gt;Crontab.guru&lt;/a&gt;
or any of the other cron generators that can be easily found via Google.&lt;/p&gt;
&lt;p&gt;E.g. &lt;code&gt;50 5 * * *&lt;/code&gt; means &amp;quot;every day at 5:50 AM UTC.&amp;quot;
&lt;a href=&quot;https://crontab.guru/examples.html&quot; class=&quot;link link-external&quot;&gt;Crontab.guru has more cron examples.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;.github/workflows/daily-build.yml&lt;/code&gt; file with the following contents
(replace the cron expression with your own):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-yaml bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Daily Netlify build trigger

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Run at 5:50 AM UTC every day&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;cron&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'50 5 * * *'&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Curl request to Netlify's build hook
        &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;BUILD_HOOK&lt;/span&gt;&lt;span class=&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; secrets.NETLIFY_DAILY_BUILD_HOOK &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
          curl -X POST -d {} &quot;$BUILD_HOOK&quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that's it!
GitHub will automatically run the Action every day around the specified time.
The Action will do a POST request to the build hook
which will trigger a build on Netlify.&lt;/p&gt;
&lt;p&gt;Note about &lt;a href=&quot;https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events&quot; class=&quot;link link-external&quot;&gt;scheduled GitHub Actions events&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;schedule&lt;/code&gt; event can be delayed
during periods of high loads of GitHub Actions workflow runs.
High load times include the start of every hour.
To decrease the chance of delay,
schedule your workflow to run at a different time of the hour.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.netlify.com/configure-builds/build-hooks/&quot; class=&quot;link link-external&quot;&gt;Build hooks on Netlify docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/reference/encrypted-secrets&quot; class=&quot;link link-external&quot;&gt;Encrypted repository secrets on GitHub docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events&quot; class=&quot;link link-external&quot;&gt;Scheduled GitHub Actions events on GitHub docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-use-absolute-import-paths-in-nodejs/</id><title>Two ways to use absolute import paths in Node.js</title><link href="https://mtsknn.fi/blog/how-to-use-absolute-import-paths-in-nodejs/" /><published>2021-06-17T12:00:00+03:00</published><updated>2023-11-02T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Node.js"></category><content type="html">&lt;p&gt;Say goodbye to &lt;code&gt;../&lt;/code&gt; times million
and use absolute import paths from the app's root directory instead.
Two contenders: Basetag and Sultan's &lt;code&gt;sexy-require&lt;/code&gt;! 🤺&lt;/p&gt;
&lt;h2 id=&quot;sultans-sexy-require&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sultans-sexy-require&quot;&gt;Sultan's &lt;code&gt;sexy-require&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Example usage of the
&lt;a href=&quot;https://github.com/sultan99/sexy-require&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;sexy-require&lt;/code&gt; npm package by Sultan&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before, unclear what's being required 👎&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'../../../database/user'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After, absolute path from the app's root dir 👍&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/database/user'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Alternatively, using an alias configured in a `.paths` file 👍&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'$db/user'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sexy-require&lt;/code&gt; overrides &lt;code&gt;Module.prototype.require&lt;/code&gt;,
so in other files
&lt;code&gt;require()&lt;/code&gt; points to &lt;code&gt;sexy-require&lt;/code&gt;'s &lt;code&gt;require&lt;/code&gt; function
which supports absolute paths and path aliases.&lt;/p&gt;
&lt;h3 id=&quot;pros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pros&quot;&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Simple to set up:
install the package
and require it in your main application file.&lt;/li&gt;
&lt;li&gt;Supports path aliases.&lt;/li&gt;
&lt;li&gt;The name!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cons&quot;&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Breaks VS Code's IntelliSense.&lt;/li&gt;
&lt;li&gt;Breaks path autocompletion in VS Code.&lt;/li&gt;
&lt;li&gt;Supports only &lt;code&gt;require()&lt;/code&gt;, not &lt;code&gt;import&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;basetag&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#basetag&quot;&gt;Basetag&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Example usage of the
&lt;a href=&quot;https://github.com/janniks/basetag&quot; class=&quot;link link-external&quot;&gt;Basetag npm package by Jannik&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before, unclear what's being required 👎&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; user &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'../../../database/user'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'../../../database/user'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After, $ points to the app's root dir 👍&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; user &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'$/database/user'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'$/database/user'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basetag creates a symlink,
or something called a junction on Windows,
so that &lt;code&gt;node_modules/$&lt;/code&gt; points to the app's root directory.&lt;/p&gt;
&lt;h3 id=&quot;pros-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pros-1&quot;&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Works with VS Code's IntelliSense.&lt;/li&gt;
&lt;li&gt;Path autocompletion works in VS Code.&lt;/li&gt;
&lt;li&gt;Supports both &lt;code&gt;require()&lt;/code&gt; and &lt;code&gt;import&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cons-1&quot;&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No way to configure path aliases.&lt;/li&gt;
&lt;li&gt;The symlink gets removed by npm when installing or removing packages,
so you need to e.g. create a &lt;code&gt;postinstall&lt;/code&gt; npm script
as instructed in the package's readme.
Not difficult,
but a little hassle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;which-one-to-use&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#which-one-to-use&quot;&gt;Which one to use&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I'm not sure which one I like more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better VS Code support of Basetag.&lt;/li&gt;
&lt;li&gt;The name &lt;em&gt;Sultan's &lt;code&gt;sexy-require&lt;/code&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just kidding –
use &lt;a href=&quot;https://github.com/janniks/basetag&quot; class=&quot;link link-external&quot;&gt;Basetag&lt;/a&gt;,
good IDE support is more important.
Plus it also supports &lt;code&gt;import&lt;/code&gt; statements.&lt;/p&gt;
&lt;h2 id=&quot;update-in-2023&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#update-in-2023&quot;&gt;Update in 2023&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are probably better solutions than these two.
Besides, I wrote this post mainly because I found the name &amp;quot;Sultan's &lt;code&gt;sexy-require&lt;/code&gt;&amp;quot; so sweet.&lt;/p&gt;
&lt;p&gt;Some time ago I came across a blog post saying that
&lt;a href=&quot;https://abhijithota.me/posts/node-import-aliases/&quot; class=&quot;link link-external&quot;&gt;Node.js supports import aliases natively since v14&lt;/a&gt;.
I haven't tested that, but it looks promising.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/smoke-testing/</id><title>Smoke testing is quick and dirty testing</title><link href="https://mtsknn.fi/blog/smoke-testing/" /><published>2021-06-13T12:00:00+03:00</published><updated>2023-02-28T12:00:00+03:00</updated><category term="Testing"></category><content type="html">&lt;p&gt;Smoke testing is cursory or &amp;quot;quick and dirty&amp;quot; testing
to see that the software works correctly.&lt;/p&gt;
&lt;h2 id=&quot;smoke-testing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#smoke-testing&quot;&gt;Smoke testing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recently heard the term &amp;quot;smoke testing&amp;quot;
when we were talking about production deployments at work.
Let's see
&lt;a href=&quot;https://en.wikipedia.org/wiki/Smoke_testing_(software)&quot; class=&quot;link link-external&quot;&gt;what Wikipedia tells us about &lt;em&gt;Smoke testing (software)&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer programming and software testing,
smoke testing
(also confidence testing,
sanity testing,
build verification test (BVT)
and build acceptance test)
is preliminary testing to reveal simple failures severe enough to,
for example,
reject a prospective software release.
Smoke tests are a subset of test cases
that cover the most important functionality of a component or system,
used to aid assessment of whether main functions of the software
appear to work correctly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So: smoke testing is cursory or &amp;quot;quick and dirty&amp;quot; testing
to see that the software works correctly.
Or appears to work correctly –
there's no extensive testing.&lt;/p&gt;
&lt;p&gt;For example,
if you do extensive testing in your integration or staging environment
(or whatever your non-production test environment is called),
there might be no need to repeat the extensive tests in production.
So, during production deployments it's enough
to verify that everything looks good at a cursory glance.
That's smoke testing.&lt;/p&gt;
&lt;h3 id=&quot;sanity-testing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sanity-testing&quot;&gt;Sanity testing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Wikipedia quote above
says that smoke testing is also called sanity testing.
This may or may not be true –
check out
&lt;a href=&quot;https://stackoverflow.com/q/28605496/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;What is the difference between smoke testing and sanity testing?&lt;/em&gt; on Stack Overflow&lt;/a&gt;
for different opinions.&lt;/p&gt;
&lt;h2 id=&quot;origin-of-the-term&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#origin-of-the-term&quot;&gt;Origin of the term&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was curious why smoke testing was called like that.
&lt;a href=&quot;https://en.wikipedia.org/wiki/Smoke_testing_(electrical)&quot; class=&quot;link link-external&quot;&gt;Wikipedia's page about &lt;em&gt;Smoke testing (electrical)&lt;/em&gt;&lt;/a&gt;
explains it clearly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The expression probably was first used in plumbing
in referring to tests for the detection of cracks, leaks or breaks
in closed systems of pipes.
By metaphorical extension the term is used in electronics.
In &lt;em&gt;Lessons Learned in Software Testing&lt;/em&gt;,
Cem Kaner, James Bach, and Brett Pettichord
provided the origin of the term:
&amp;quot;The phrase &lt;em&gt;smoke test&lt;/em&gt; comes from electronic hardware testing.
You plug in a new board and turn on the power.
If you see smoke coming from the board, turn off the power.
You don't have to do any more testing.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So: plumbing → electronic hardware testing → software testing.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/interdependent-react-prop-types-in-ts/</id><title>React + TypeScript: Interdependent prop types</title><link href="https://mtsknn.fi/blog/interdependent-react-prop-types-in-ts/" /><published>2021-06-13T12:00:00+03:00</published><updated>2023-03-01T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;I.e. props that depend on other props.
You can require and forbid certain prop combinations
by utilizing TypeScript's union and intersection types.&lt;/p&gt;
&lt;h2 id=&quot;example-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-problem&quot;&gt;Example problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's say we want to create a &lt;code&gt;Shape&lt;/code&gt; React component
with the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It takes a &lt;code&gt;color&lt;/code&gt; prop.&lt;/li&gt;
&lt;li&gt;It takes a &lt;code&gt;type&lt;/code&gt; prop
with the value of &lt;code&gt;'circle'&lt;/code&gt;, &lt;code&gt;'square'&lt;/code&gt; or &lt;code&gt;'rectangle'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Depending on the &lt;code&gt;type&lt;/code&gt; prop's value,
it takes the following props as well:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;radius&lt;/code&gt; when the type is &lt;code&gt;'circle'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;width&lt;/code&gt; when the type is &lt;code&gt;'square'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; when the type is &lt;code&gt;'rectangle'&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A naive type for the props object would look like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShapeProps&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;
  color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'circle'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'square'&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'rectangle'&lt;/span&gt;
  radius&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
  width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
  height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&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 function&quot;&gt;Shape&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ShapeProps&lt;span class=&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 comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's naive because we could specify &lt;em&gt;all&lt;/em&gt; of those props:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-tsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;&lt;span class=&quot;token class-name&quot;&gt;Shape&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;color&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;red&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;circle&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That makes no sense because a circle shape doesn't have a width or a height;
it only has a radius.&lt;/p&gt;
&lt;p&gt;The other shapes have similar problems.&lt;/p&gt;
&lt;h2 id=&quot;union-type-to-the-rescue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#union-type-to-the-rescue&quot;&gt;Union type to the rescue&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We instead want to create a
&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types&quot; class=&quot;link link-external&quot;&gt;union type&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShapeProps&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 punctuation&quot;&gt;{&lt;/span&gt; color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'circle'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; radius&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&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; color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'square'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&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; color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'rectangle'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now TypeScript won't let us specify invalid props.&lt;/p&gt;
&lt;p&gt;For example, when the type is &lt;code&gt;'circle'&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can (and must) specify only the &lt;code&gt;color&lt;/code&gt; and &lt;code&gt;radius&lt;/code&gt; props.&lt;/li&gt;
&lt;li&gt;We can't specify the &lt;code&gt;width&lt;/code&gt; or &lt;code&gt;height&lt;/code&gt; props;
doing so would produce an error.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;simplify-with-an-intersection-type&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#simplify-with-an-intersection-type&quot;&gt;Simplify with an intersection type&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Notice how we are repeating the &lt;code&gt;color&lt;/code&gt; prop in all three types.&lt;/p&gt;
&lt;p&gt;We can reduce duplication by using an
&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types&quot; class=&quot;link link-external&quot;&gt;intersection type&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShapeProps&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; color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&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; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'circle'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; radius&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&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; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'square'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&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; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'rectangle'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &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;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;more-tricks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#more-tricks&quot;&gt;More tricks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I learned this trick from Bruno Antunes's
&lt;a href=&quot;https://www.youtube.com/watch?v=vXh4PFwZFGI&quot; class=&quot;link link-external&quot;&gt;YouTube video &lt;em&gt;React.js TypeScript Conditional Props – Props that depend on other Props&lt;/em&gt; (26:13)&lt;/a&gt;.
Check it out, it has more advanced examples as well.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/5-rules-of-aria/</id><title>The 5 rules of ARIA</title><link href="https://mtsknn.fi/blog/5-rules-of-aria/" /><published>2021-06-13T12:00:00+03:00</published><updated>2023-03-02T12:00:00+03:00</updated><category term="Accessibility"></category><content type="html">&lt;p&gt;Five simple rules for using ARIA attributes,
straight from W3C.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/using-aria/&quot; class=&quot;link link-external&quot;&gt;W3C's &lt;em&gt;Using ARIA&lt;/em&gt; document&lt;/a&gt;
has a &lt;a href=&quot;https://www.w3.org/TR/using-aria/#notes2&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Notes on ARIA Use in HTML&lt;/em&gt; section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It's a short section,
and here's an even shorter summary:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If you &lt;em&gt;can&lt;/em&gt; use a native HTML element or attribute [...] instead of [...] an ARIA role, state or property [...], &lt;strong&gt;then do so&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do not change native semantics, unless you really have to.&lt;/p&gt;
&lt;p&gt;For example: Developer wants to build a heading that's a tab.&lt;/p&gt;
&lt;p&gt;Do &lt;strong&gt;not&lt;/strong&gt; do this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&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;tab&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;heading tab&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Do&lt;/strong&gt; this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&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;tab&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;heading tab&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;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All interactive ARIA controls must be usable with the keyboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do not use &lt;code&gt;role=&amp;quot;presentation&amp;quot;&lt;/code&gt; or &lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt; on a &lt;strong&gt;focusable&lt;/strong&gt; element.&lt;/p&gt;
&lt;p&gt;Using either of these on a &lt;strong&gt;focusable&lt;/strong&gt; element will result in some users focusing on 'nothing'.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All interactive elements must have an accessible name.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Inspired by &lt;a href=&quot;https://www.bram.us/2021/05/26/the-5-rules-of-aria/&quot; class=&quot;link link-external&quot;&gt;Bramus's summary of the five rules&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/goodbye-cookbook-hello-more-blog-posts/</id><title>Goodbye Cookbook, hello more blog posts</title><link href="https://mtsknn.fi/blog/goodbye-cookbook-hello-more-blog-posts/" /><published>2021-06-12T12:00:00+03:00</published><updated>2023-03-17T12:00:00+03:00</updated><category term="Blogging"></category><content type="html">&lt;p&gt;I ditched my website's Cookbook section
and converted existing recipes to blog posts.
Mostly to reduce stress
and make things clearer.&lt;/p&gt;
&lt;p&gt;Up until today,
my website had a Cookbook section
which contained &amp;quot;technical recipes&amp;quot;:
short tips, tricks and code snippets.&lt;/p&gt;
&lt;p&gt;Today I converted all existing cookbook recipes to blog posts.&lt;/p&gt;
&lt;p&gt;I wasn't sure which articles should be cookbook recipes
and which articles should be blog posts.
Some blog posts already felt like they should be cookbook recipes,
and vice versa.&lt;/p&gt;
&lt;p&gt;The cookbook just caused extra stress in the end
because I had two things to maintain:
the blog and the cookbook.
Or actually three things,
since &lt;a href=&quot;/blog/bye-weekly-log/&quot; class=&quot;link&quot;&gt;I am (update: was) also writing a weekly log&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At some point I almost had the idea
to make two versions of some articles:
a long and detailed blog post,
and a short and straight-to-the-point cookbook recipe.&lt;/p&gt;
&lt;p&gt;But that would have been silly:
double work for no apparent reason.
If a blog post is long,
I'll rather include a short summary
or split it into smaller posts.
If a blog post is short,
that's fine too!&lt;/p&gt;
&lt;p&gt;The &amp;quot;downside&amp;quot; of removing the cookbook
is that I really like the terms &amp;quot;cookbook&amp;quot; and &amp;quot;recipe.&amp;quot;
I think I was inspired by
&lt;a href=&quot;https://getkirby.com/docs/cookbook&quot; class=&quot;link link-external&quot;&gt;Kirby CMS's cookbook section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another source of inspiration was
&lt;a href=&quot;https://notes.zander.wtf/&quot; class=&quot;link link-external&quot;&gt;Zander Martineau's &lt;em&gt;Code Notes&lt;/em&gt;&lt;/a&gt;.
I found it a year ago via his blog post
&lt;a href=&quot;https://zander.wtf/blog/code-notes-release&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Announcing Code Notes&lt;/em&gt;&lt;/a&gt;.
Cool!
I have now tried out something similar (though much simpler),
and I'll rather keep my code notes under my blog.&lt;/p&gt;
&lt;p&gt;All right,
now I have more time and energy to write blog posts...
or at least I hope so. 😅&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/my-favorite-mnemonics-for-american-vs-british-english/</id><title>My favorite mnemonics for American vs British English</title><link href="https://mtsknn.fi/blog/my-favorite-mnemonics-for-american-vs-british-english/" /><published>2021-06-11T12:00:00+03:00</published><updated>2021-06-11T12:00:00+03:00</updated><category term="English"></category><category term="Mnemonics"></category><content type="html">&lt;p&gt;Use these weird tricks to remember
which words are American English
and which are British English.
Linguists HATE them!&lt;/p&gt;
&lt;h2 id=&quot;learned-vs-learnt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#learned-vs-learnt&quot;&gt;Learned vs learnt&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&amp;quot;Learned&amp;quot; is American English,
&amp;quot;learnt&amp;quot; is British English.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mnemonic:&lt;/strong&gt;
Englishmen like to drink &lt;strong&gt;tea&lt;/strong&gt;,
so the word ends in a &lt;strong&gt;t&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Source of the mnemonic:
&lt;a href=&quot;https://www.grammarly.com/blog/learned-learnt/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Learned or Learnt?&lt;/em&gt; on Grammarly&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;words-ending-in-er-vs-re&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#words-ending-in-er-vs-re&quot;&gt;Words ending in &amp;quot;-er&amp;quot; vs &amp;quot;-re&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many words end in &amp;quot;-er&amp;quot; in American English
and in &amp;quot;-re&amp;quot; in British English.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;American English&lt;/th&gt;
&lt;th&gt;British English&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;center&lt;/td&gt;
&lt;td&gt;centre&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fiber&lt;/td&gt;
&lt;td&gt;fibre&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;liter&lt;/td&gt;
&lt;td&gt;litre&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;meter&lt;/td&gt;
&lt;td&gt;metre&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;theater or theatre&lt;/td&gt;
&lt;td&gt;theatre&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that in American English,
&lt;em&gt;theater&lt;/em&gt; is the standard spelling,
but the &lt;em&gt;-re&lt;/em&gt; spelling is also commonly used,
especially in proper names
(&lt;em&gt;the Lunt-Fontanne Theatre&lt;/em&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Source of the rule and the quote:
&lt;a href=&quot;https://www.lexico.com/grammar/words-ending-in-re-er&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Words ending in &amp;quot;-re&amp;quot; and &amp;quot;-er&amp;quot;&lt;/em&gt; on Lexico&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mnemonic:&lt;/strong&gt;
in Am-&lt;strong&gt;er&lt;/strong&gt;-ican English,
many words end in &amp;quot;-&lt;strong&gt;er&lt;/strong&gt;.&amp;quot;&lt;/p&gt;
&lt;p&gt;Source of the mnemonic: me!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/squircley/</id><title>Squircley is an SVG squircle generator</title><link href="https://mtsknn.fi/blog/squircley/" /><published>2021-06-06T12:00:00+03:00</published><updated>2021-06-06T12:00:00+03:00</updated><category term="Cool tools"></category><category term="SVG"></category><content type="html">&lt;p&gt;A squircle is a rounded square with no straight edges;
the shape is a continuous curve.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://squircley.app/&quot; class=&quot;link link-external&quot;&gt;Squircley&lt;/a&gt;
is a simple tool for creating SVG &amp;quot;squircles.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./squircley.png&quot; alt=&quot;Screenshot of the Squircley app, showing a yellow squircle and controls for customizing it.&quot;&gt;&lt;/p&gt;
&lt;p&gt;From the author's (George Francis)
dev.to article &lt;a href=&quot;https://dev.to/georgedoescode/codepen-soften-up-your-designs-with-a-squircle-3nd3&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Soften up your designs with a Squircle!&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Squircle,
unlike an element with border-radius set,
has no straight edges at all.
The shape is a continuous curve!
Apple love this trick and use it in both physical and digital design.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I &lt;em&gt;love&lt;/em&gt; how squircles look! 🤩
Though funnily &lt;a href=&quot;https://hanki.dev/&quot; class=&quot;link link-external&quot;&gt;my brother&lt;/a&gt; doesn't like them,
apparently because at some point
they have been popular in Android as well
so he has already received an overdose of them. 🤔&lt;/p&gt;
&lt;p&gt;But I like them so
&lt;a href=&quot;https://squircley.app/&quot; class=&quot;link link-external&quot;&gt;check out Squircley&lt;/a&gt;
and &lt;a href=&quot;https://dev.to/georgedoescode/codepen-soften-up-your-designs-with-a-squircle-3nd3&quot; class=&quot;link link-external&quot;&gt;see the dev.to article for an interactive example&lt;/a&gt;!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/kayaking/</id><title>Kayaking is fun</title><link href="https://mtsknn.fi/blog/kayaking/" /><published>2021-06-06T12:00:00+03:00</published><updated>2021-06-06T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;I kayaked for the first time in my life and quite liked it.
Then I ate pizza.&lt;/p&gt;
&lt;h2 id=&quot;kayaking&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#kayaking&quot;&gt;Kayaking&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We went kayaking with our team on Tuesday.
Here's a photo that I took
using my phone's (Unihertz Jelly) potato camera:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./kayaking-team.jpg&quot; alt=&quot;A photo taken from a red kayak which is partly showing in the bottom right corner. Eight other kayaks are in the background with people (my teammates) in them with their backs toward me. There are trees on the shores and buildings in the distant horizon.&quot;&gt;&lt;/p&gt;
&lt;p&gt;And here's a quick selfie that I snapped for my wife (nice picture 😂):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./kayaking-selfie.jpg&quot; alt=&quot;My selfie as I'm kayaking. Only my head is shown, I'm grinning widely with my teeth showing. Behind me is water and trees. My face is not focused properly which makes the photo silly.&quot;&gt;&lt;/p&gt;
&lt;p&gt;It was my first time kayaking.
It was quite fun but also surprisingly effortful
as I had to use my legs to maintain balance
and my arms and upper torso to move the kayak forward.&lt;/p&gt;
&lt;p&gt;I can definitely recommend trying out kayaking.&lt;/p&gt;
&lt;h2 id=&quot;pizza&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pizza&quot;&gt;Pizza&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Afterwards we went eating.
Some chose fancy foods like entrecôte,
but I chose an exotic pizza. 😋
No picture of it, sadly, but here are the ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tomato sauce&lt;/li&gt;
&lt;li&gt;mozzarella cheese&lt;/li&gt;
&lt;li&gt;spreadable Nduja salami&lt;/li&gt;
&lt;li&gt;hot Spianata salami&lt;/li&gt;
&lt;li&gt;blood grapefruit marmalade&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Eruca_vesicaria&quot; class=&quot;link link-external&quot;&gt;rocket/arugula&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;parmesan cheese&lt;/li&gt;
&lt;li&gt;virgin olive oil.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It wasn't very &lt;em&gt;delicious&lt;/em&gt;,
but I wanted something exotic,
and it was exotic. ¯\(ツ)/¯&lt;/p&gt;
&lt;p&gt;I can definitely recommend trying out pizza too!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/react-use-state-machine/</id><title>`useStateMachine`: &amp;half;&amp;nbsp;kB state machine hook for React</title><link href="https://mtsknn.fi/blog/react-use-state-machine/" /><published>2021-05-30T12:00:00+03:00</published><updated>2021-05-30T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;A state machine is a bit like &lt;code&gt;useReducer&lt;/code&gt;,
but with greater constraints (in a good way).
This state machine hook is tiny.&lt;/p&gt;
&lt;p&gt;Cassio Zen's
&lt;a href=&quot;https://github.com/cassiozen/useStateMachine&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;useStateMachine&lt;/code&gt; hook for React&lt;/a&gt;
is a tiny (less than half a kilobyte) package
for creating state machines.
Pair it with &lt;a href=&quot;https://preactjs.com/&quot; class=&quot;link link-external&quot;&gt;Preact&lt;/a&gt;,
and you have a very small yet powerful bundle
for creating stateful UIs.&lt;/p&gt;
&lt;p&gt;If you are not familiar with state machines,
Cassio explains them in his
&lt;a href=&quot;https://www.youtube.com/watch?v=N0OaRdJuVlc&quot; class=&quot;link link-external&quot;&gt;YouTube video &lt;em&gt;Getting your act together with State Machines&lt;/em&gt; (12:35)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;State machines are somewhat similar to reducers.
From one comment by Cassio under the video:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It's similar,
but with one important distinction:
with useReducer/redux you can always dispatch any action,
and it will always reach the reducer.
With state machines,
the current state dictates which transitions you can &amp;quot;dispatch&amp;quot; next.&lt;/p&gt;
&lt;p&gt;And this small change has a big impact
because it empowers you to create your own constraints in the code
to make a more robust application.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the video,
Cassio uses
&lt;a href=&quot;https://github.com/davidkpiano/xstate&quot; class=&quot;link link-external&quot;&gt;a popular state machine library called XState&lt;/a&gt;,
but the main idea is the same.
Sidenotes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;XState is more featureful,
but also weighs more,
about 19 kB
(including the &lt;code&gt;@xstate/react&lt;/code&gt; package required by React).
Other differences are mentioned in
&lt;a href=&quot;https://github.com/cassiozen/useStateMachine/wiki/XState-comparison&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;useStateMachine&lt;/code&gt;'s Wiki page &lt;em&gt;XState comparison&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;There's also
&lt;a href=&quot;https://github.com/davidkpiano/xstate/tree/main/packages/xstate-fsm&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;@xstate/fsm&lt;/code&gt;, a 1 kB implementation of XState&lt;/a&gt;.
Some differences are mentioned in
&lt;a href=&quot;https://github.com/cassiozen/useStateMachine/issues/27&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;useStateMachine&lt;/code&gt;'s issue #27&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two more good videos by Cassio on the topic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=jF1tO2hTdC0&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Custom State Machine Hook with useReducer &amp;amp; useEffect&lt;/em&gt; (28:36)&lt;/a&gt;
goes through implementing &lt;code&gt;useStateMachine&lt;/code&gt; from scratch.
The latest version of the library is a bit more robust
(and also a bit more cryptic since it's written in fancy TypeScript).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=uT-f6UJBqFE&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;React useStateMachine hook&lt;/em&gt; (18:17)&lt;/a&gt;
shows two examples
how to use the &lt;code&gt;useStateMachine&lt;/code&gt; hook.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/daily-stand-ups/</id><title>Sprint-centric vs people-centric daily stand-up meetings</title><link href="https://mtsknn.fi/blog/daily-stand-ups/" /><published>2021-05-30T12:00:00+03:00</published><updated>2021-05-30T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;A daily stand-up should focus on the sprint.
But it should also be about the team members.&lt;/p&gt;
&lt;p&gt;In January,
I read Critter's (Mike Crittenden) blog post
&lt;a href=&quot;https://critter.blog/2020/08/17/zombie-standups-try-walking-the-board/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Zombie standups? Try walking the board&lt;/em&gt;&lt;/a&gt;.
Since then,
we have been practicing &lt;em&gt;sprint-centric&lt;/em&gt; daily stand-ups in our team.
Instead of going person by person,
we go ticket by ticket.&lt;/p&gt;
&lt;p&gt;I think it was a step in the right direction.
Previously our daily stand-ups were more chaotic,
often not focusing on the sprint enough.&lt;/p&gt;
&lt;p&gt;But there's a but.
The downside is that there's no good opportunity to discuss ad hoc things.
Critter does cover this in his blog post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;But what about general announcements the team needs to hear?&lt;/em&gt;
After you walk the board,
ask &amp;quot;any general things we need to discuss?&amp;quot; and let people speak up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;...but that hasn't worked well.
Maybe opening your mouth at the end is just too difficult.
For example, some people are shy.&lt;/p&gt;
&lt;p&gt;This week we changed back to &lt;em&gt;people-centric&lt;/em&gt; daily stand-ups.
To help us keep the main focus on the sprint and its goals,
I created quick filters in Jira for each person.
For example,
when it's my turn to speak,
I activate the &amp;quot;Matias&amp;quot; quick filter
so that only tasks assigned to me
are showing on the board.
Then it's easy for me to talk about my tasks
&lt;em&gt;plus&lt;/em&gt; state any other things I have on my mind
because I'm already speaking.&lt;/p&gt;
&lt;p&gt;The upside so far has been that there has been more ad hoc discussion,
meaning more sharing of information relevant to the team.&lt;/p&gt;
&lt;p&gt;We'll see in the coming weeks
whether this &amp;quot;new old&amp;quot; way of doing daily stand-ups is better or worse.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/cursive-parinfer/</id><title>Cursive (Clojure IDE) supports Parinfer out of the box</title><link href="https://mtsknn.fi/blog/cursive-parinfer/" /><published>2021-05-30T12:00:00+03:00</published><updated>2021-05-30T12:00:00+03:00</updated><category term="Clojure"></category><content type="html">&lt;p&gt;It's not mentioned in the docs or anywhere,
but you can enable Parinfer from Cursive's settings.
Works great with IdeaVim.&lt;/p&gt;
&lt;h2 id=&quot;paredit-bad-for-me&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#paredit-bad-for-me&quot;&gt;Paredit bad (for me)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cursive-ide.com/&quot; class=&quot;link link-external&quot;&gt;Cursive, the IDE for Clojure and ClojureScript&lt;/a&gt;,
uses &lt;a href=&quot;https://cursive-ide.com/userguide/paredit.html&quot; class=&quot;link link-external&quot;&gt;Paredit for structural editing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Editing code in Cursive has been a hassle
because I'm using IdeaVim (a Vim plugin for Cursive and other IntelliJ-based IDEs)
and haven't configured keybindings for Paredit.
I haven't found any good tutorials on that,
so it feels overwhelming.
(Otherwise I have liked Cursive when doing
Clojure exercises on &lt;a href=&quot;https://exercism.org/&quot; class=&quot;link link-external&quot;&gt;Exercism&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id=&quot;parinfer-good-and-how-to-enable-it-in-cursive&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#parinfer-good-and-how-to-enable-it-in-cursive&quot;&gt;Parinfer good (and how to enable it in Cursive)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have dreamed of using &lt;a href=&quot;https://shaunlebron.github.io/parinfer/&quot; class=&quot;link link-external&quot;&gt;Parinfer&lt;/a&gt; in Cursive.
Parinfer seems so much easier to use than Paredit.&lt;/p&gt;
&lt;p&gt;Today my dreams came true
because turns out that Cursive supports Parinfer out of the box!
&lt;strong&gt;Go to &lt;em&gt;Settings → Editor → General → Smart Keys → Clojure&lt;/em&gt;
and choose &amp;quot;Parinfer Smart mode&amp;quot; from the &amp;quot;Structural editing style&amp;quot; dropdown.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;rant&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#rant&quot;&gt;Rant&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What's infuriating is that
there's &lt;em&gt;zero&lt;/em&gt; mention of Parinfer in the Cursive docs
or in Cursive's GitHub Wiki. 🤦‍♂️
I have wasted so much time trying to google &amp;quot;cursive ide parinfer&amp;quot;
and finding only a few mentions that &amp;quot;Cursive supports Parinfer&amp;quot;
but no information how to enable that.
I found the setting today by accident
because I was just going to disable Paredit.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/react-router-scroll-to-top/</id><title>Scrolling to top on page changes in React Router (v5)</title><link href="https://mtsknn.fi/blog/react-router-scroll-to-top/" /><published>2021-05-23T12:00:00+03:00</published><updated>2021-05-23T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;A common solution is to scroll to top every time the page changes.
That's incorrect:
the page should be scrolled to top only when navigating to &lt;em&gt;new&lt;/em&gt; pages,
not when navigating back or forward.&lt;/p&gt;
&lt;h2 id=&quot;common-but-wrong-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#common-but-wrong-solution&quot;&gt;Common but wrong solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When navigating in a Single Page Application (SPA),
you have to handle scrolling manually.
Here's a &lt;a href=&quot;https://stackoverflow.com/q/36904185/1079869&quot; class=&quot;link link-external&quot;&gt;solution that's often recommended&lt;/a&gt;,
but this is wrong:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useLocation &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react-router-dom'&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Use this hook in some top-level component&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// which is inside a `&amp;lt;Router&gt;` component&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useOnPageChange&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; pathname &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useLocation&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&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;
    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scrollTo&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 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 punctuation&quot;&gt;[&lt;/span&gt;pathname&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's wrong because
the page is scrolled to top on all page changes –
even when using the browser's back and forward navigation buttons.&lt;/p&gt;
&lt;p&gt;Compare with any non-SPA site,
like my website or &lt;a href=&quot;https://en.wikipedia.org/&quot; class=&quot;link link-external&quot;&gt;Wikipedia&lt;/a&gt;.
When using the browser's back/forward buttons,
the previous/next page's scrolling position should be restored.
&lt;strong&gt;The page should be scrolled to top only when navigating to &lt;em&gt;new&lt;/em&gt; pages.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;correct-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#correct-solution&quot;&gt;Correct solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The fix is to check the value of the
&lt;a href=&quot;https://github.com/ReactTraining/history/blob/v5.0.0/docs/api-reference.md#action&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;history&lt;/code&gt; object's &lt;code&gt;action&lt;/code&gt; parameter&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useHistory&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useLocation &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react-router-dom'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useOnPageChange&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; action &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useHistory&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; pathname &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useLocation&lt;/span&gt;&lt;span class=&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;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Do nothing when using the browser's back/forward buttons&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;action &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POP'&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;

    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scrollTo&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 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 punctuation&quot;&gt;[&lt;/span&gt;action&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pathname&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could (and probably should) also do other things in the hook,
like focus the main heading of the new page.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/emphasis-as-progressive-enhancement/</id><title>`&lt;strong&gt;` and `&lt;em&gt;` should be treated as progressive enhancement</title><link href="https://mtsknn.fi/blog/emphasis-as-progressive-enhancement/" /><published>2021-05-23T12:00:00+03:00</published><updated>2021-05-23T12:00:00+03:00</updated><category term="Accessibility"></category><content type="html">&lt;p&gt;Screen readers don't announce emphasized text,
so your text should be understandable even without the emphases.&lt;/p&gt;
&lt;p&gt;Martin Underhill writes that
&lt;a href=&quot;https://www.tempertemper.net/blog/bold-and-italics-arent-read-by-screen-readers&quot; class=&quot;link link-external&quot;&gt;bold and italics aren't read by screen readers&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Interestingly,
the NVDA screen reader added support for emphasis [in 2015],
only to remove it following complaints by users.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had noticed before
that screen readers indeed don't announce
if the currently read text is bold or italics.&lt;/p&gt;
&lt;p&gt;But I hadn't considered this mindset:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Text-level semantics like italics and bold
should be treated as a progressive enhancement.
In other words,
your sentences should make sense without emphasis;
those &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; wrappers
should just offer a nice added extra
for [sighted users].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Makes sense.&lt;/p&gt;
&lt;p&gt;Strikethrough is a similar but more difficult case
because it &lt;em&gt;adds&lt;/em&gt; content.
Read &lt;a href=&quot;https://www.tempertemper.net/blog/be-careful-with-strikethrough&quot; class=&quot;link link-external&quot;&gt;Martin's another post &lt;em&gt;Be careful with strikethrough&lt;/em&gt;&lt;/a&gt;
for more details.
The post contains several good points
why strikethrough is better avoided entirely.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/delegate-types-in-csharp-action-vs-func-vs-predicate/</id><title>Delegate types in C#: `Action` vs `Func` vs `Predicate`</title><link href="https://mtsknn.fi/blog/delegate-types-in-csharp-action-vs-func-vs-predicate/" /><published>2021-05-22T12:00:00+03:00</published><updated>2021-06-11T12:00:00+03:00</updated><category term="C#"></category><content type="html">&lt;p&gt;&lt;code&gt;Action&lt;/code&gt; doesn't return anything,
&lt;code&gt;Func&lt;/code&gt; does.
&lt;code&gt;Predicate&lt;/code&gt; takes one parameter and returns a boolean.&lt;/p&gt;
&lt;h2 id=&quot;actionlesst1-t2-t3-greater&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#actionlesst1-t2-t3-greater&quot;&gt;&lt;code&gt;Action&amp;lt;T1, T2, T3, ...&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Action&lt;/code&gt; has no return value.&lt;/li&gt;
&lt;li&gt;The types &lt;code&gt;T1&lt;/code&gt;, &lt;code&gt;T2&lt;/code&gt;, &lt;code&gt;T3&lt;/code&gt; and so on specify the parameters' types.&lt;/li&gt;
&lt;li&gt;There can be between 0 and 16 parameters:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Action&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Action&amp;lt;T1&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Action&amp;lt;T1, T2&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Action&amp;lt;T1, T2, T3&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Action&amp;lt;T1, T2, T3, ..., T16&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Action&lt;/code&gt; takes no parameters and returns nothing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Action&amp;lt;int&amp;gt;&lt;/code&gt; takes one &lt;code&gt;int&lt;/code&gt; parameter and returns nothing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Action&amp;lt;int, bool, int&amp;gt;&lt;/code&gt; takes three parameters
of types &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt;,
in that order,
and returns nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Action&lt;/span&gt; lambda1 &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;=&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;WriteLine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lambda1 was called&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// No return 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 class-name&quot;&gt;Action&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; lambda2 &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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; param1&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;WriteLine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;$&quot;lambda2 was called with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&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 comment&quot;&gt;// No return 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 class-name&quot;&gt;Action&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; lambda3 &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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; param1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;/span&gt; param2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; param3&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;WriteLine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;$&quot;lambda3 was called with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param1&lt;/span&gt;&lt;span class=&quot;token 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 punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; and &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&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 comment&quot;&gt;// No return 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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;funclesst1-t2-t3-tresultgreater&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#funclesst1-t2-t3-tresultgreater&quot;&gt;&lt;code&gt;Func&amp;lt;T1, T2, T3, ..., TResult&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Func&lt;/code&gt; returns a value of type &lt;code&gt;TResult&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The types &lt;code&gt;T1&lt;/code&gt;, &lt;code&gt;T2&lt;/code&gt;, &lt;code&gt;T3&lt;/code&gt; and so on specify the parameters' types.&lt;/li&gt;
&lt;li&gt;There can be between 0 and 16 parameters:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;TResult&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;T1, TResult&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;T1, T2, TResult&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;T1, T2, T3, TResult&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;T1, T2, T3, ..., T16, TResult&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TResult&lt;/code&gt; is always in the last position,
i.e. the last type always specifies the return value's type.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;string&amp;gt;&lt;/code&gt; takes no parameters and returns a &lt;code&gt;string&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;int, string&amp;gt;&lt;/code&gt; takes one &lt;code&gt;int&lt;/code&gt; parameter and returns a &lt;code&gt;string&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;int, bool, int, string&amp;gt;&lt;/code&gt; takes three parameters
of types &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt;,
in that order,
and returns a &lt;code&gt;string&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Func&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; lambda1 &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;=&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lambda1 was called&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;

&lt;span class=&quot;token class-name&quot;&gt;Func&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; lambda2 &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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; param1&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 interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;$&quot;lambda2 was called with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&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 class-name&quot;&gt;Func&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; lambda3 &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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; param1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;/span&gt; param2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; param3&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 comment&quot;&gt;// `null` return value is ok too&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// because strings can be null&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;param2&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 keyword&quot;&gt;null&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 interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;$&quot;lambda3 was called with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param1&lt;/span&gt;&lt;span class=&quot;token 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 punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; and &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token expression language-csharp&quot;&gt;param3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;predicatelesstgreater&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#predicatelesstgreater&quot;&gt;&lt;code&gt;Predicate&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Predicate&lt;/code&gt; returns a boolean.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Predicate&lt;/code&gt; takes one parameter of type &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Predicate&amp;lt;int&amp;gt;&lt;/code&gt; takes one &lt;code&gt;int&lt;/code&gt; parameter and returns a boolean.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Predicate&amp;lt;string&amp;gt;&lt;/code&gt; takes one &lt;code&gt;string&lt;/code&gt; parameter and returns a boolean.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Predicate&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; IsPositive &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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; param&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; param &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;Predicate&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; StartsWithFoo &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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; param&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; param&lt;span class=&quot;token punctuation&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;StartsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&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 boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;predicatelesstgreater-vs-funclesst-boolgreater&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#predicatelesstgreater-vs-funclesst-boolgreater&quot;&gt;&lt;code&gt;Predicate&amp;lt;T&amp;gt;&lt;/code&gt; vs &lt;code&gt;Func&amp;lt;T, bool&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Predicate&amp;lt;T&amp;gt;&lt;/code&gt; is effectively the same as &lt;code&gt;Func&amp;lt;T, bool&amp;gt;&lt;/code&gt;.
They both take a single parameter of type &lt;code&gt;T&lt;/code&gt;
and return a boolean.&lt;/p&gt;
&lt;p&gt;That said,
&lt;a href=&quot;https://stackoverflow.com/a/665572/1079869&quot; class=&quot;link link-external&quot;&gt;they are not assignment-compatible&lt;/a&gt;.
Example from the linked Stack Overflow answer by Daniel Earwicker
(slightly modified):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IsNegative&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; x&lt;span class=&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; x &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&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; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Predicate&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; p &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; IsNegative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Func&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; f &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; IsNegative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    p &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Doesn't work&lt;/span&gt;
    f &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Doesn't work&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which one to use,
&lt;code&gt;Predicate&amp;lt;T&amp;gt;&lt;/code&gt; or &lt;code&gt;Func&amp;lt;T, bool&amp;gt;&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;If you can choose,
my hunch is that &lt;code&gt;Func&lt;/code&gt; is better because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Func&lt;/code&gt; has overloads that take more than one input type,
so it's more flexible than &lt;code&gt;Predicate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Func&amp;lt;T, bool&amp;gt;&lt;/code&gt; is clear (given that you know how &lt;code&gt;Func&lt;/code&gt;s work),
whereas &lt;code&gt;Predicate&lt;/code&gt; is more niche
and makes sense only if you know what a &amp;quot;predicate&amp;quot; is.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the other hand,
&lt;code&gt;Predicate&amp;lt;T&amp;gt;&lt;/code&gt; is short and descriptive,
so I don't have a strong opinion
which one to prefer.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This blog post was inspired by
Scott Steffes's
&lt;a href=&quot;https://www.youtube.com/watch?v=E-g8Ivss0Gs&quot; class=&quot;link link-external&quot;&gt;YouTube video &lt;em&gt;Generic Delegate Types (Action, Func, Predicate), in C#&lt;/em&gt;&lt;/a&gt;.
There's interesting discussion about the delegate keyword versus lambda syntax
in &lt;a href=&quot;https://old.reddit.com/r/csharp/comments/lzmn7y/whenever_i_need_to_pass_a_function_into_another/&quot; class=&quot;link link-external&quot;&gt;a Reddit thread around the video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See also these pages in the .NET docs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.action?view=net-5.0&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Action&lt;/code&gt; Delegate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.func-1?view=net-5.0&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Func&amp;lt;TResult&amp;gt;&lt;/code&gt; Delegate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.predicate-1?view=net-5.0&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Predicate&amp;lt;T&amp;gt;&lt;/code&gt; Delegate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/comment-terminal-commands/</id><title>Comment terminal commands to find them later more easily</title><link href="https://mtsknn.fi/blog/comment-terminal-commands/" /><published>2021-05-15T12:00:00+03:00</published><updated>2021-05-15T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;If you append a comment (like &lt;code&gt;# foo&lt;/code&gt;) to a terminal command,
you can search by the comment text when using &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;R&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;Full example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; http://1.2.3.4/linux.iso  &lt;span class=&quot;token comment&quot;&gt;# Fred's distribution of Linux&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Later you can press &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;R&lt;/kbd&gt;
and search for e.g. &amp;quot;Fred&amp;quot; to find the command.&lt;/p&gt;
&lt;p&gt;The example is from
climagic's &lt;a href=&quot;https://www.youtube.com/watch?v=UvZY7bYt2Lo&quot; class=&quot;link link-external&quot;&gt;YouTube video &lt;em&gt;Using comments in the interactive shell&lt;/em&gt; (3:32)&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/4-1-wrapping-styles-for-markdown-prose-and-code-comments/</id><title>4 + 1 wrapping styles for Markdown prose and code comments</title><link href="https://mtsknn.fi/blog/4-1-wrapping-styles-for-markdown-prose-and-code-comments/" /><published>2021-05-12T12:00:00+03:00</published><updated>2021-05-12T12:00:00+03:00</updated><category term="Clean code"></category><category term="Documentation"></category><category term="Markdown"></category><content type="html">&lt;p&gt;A paragraph per line,
a sentence per line,
or hard wrapping at e.g. 80 characters?
These days I prefer a fourth option:
semantic line breaks.&lt;/p&gt;
&lt;h2 id=&quot;context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#context&quot;&gt;Context&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a long time
I used to hard wrap my Markdown prose and code comments at 80 characters.
It looked quite neat.&lt;/p&gt;
&lt;p&gt;When a certain colleague touched the same files,
he always changed the wrapping style to a sentence per line.
Not necessarily for the whole documents,
but for the parts that he had modified,
e.g. a section in a Markdown file.&lt;/p&gt;
&lt;p&gt;I didn't like it at first.
My beautiful hard wrapped prose!
I was too shy to complain about it,
and it wasn't actually that big of a deal.&lt;/p&gt;
&lt;p&gt;Eventually I started to like the new style.
Now I think it was a step in the right direction.&lt;/p&gt;
&lt;h2 id=&quot;benefits-of-a-consistent-wrapping-style&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#benefits-of-a-consistent-wrapping-style&quot;&gt;Benefits of a consistent wrapping style&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Why does it matter
how you wrap Markdown prose and code comments?
While pondering over something like this
may seem superficial,
a good wrapping style does provide benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Readability.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Code is read more often than it's written,
so readability is important.
Readability also helps with writing and editing longer pieces of text.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintainability.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example:
if you hard wrap at 80 characters,
anyone editing the text has to manually update and tweak the wrapping,
which can be annoying.
Or you can use a tool,
but finding a suitable tool and installing and configuring it
is one more thing to worry about.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Diffability (version controlling).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example:
if you have a long paragraph on a single line,
changing one word highlights the whole paragraph
in a Git diff.
If you instead have a single sentence
or even half a sentence
on a single line,
changing one word highlights just that single sentence / half a sentence.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;not-limited-to-markdown&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#not-limited-to-markdown&quot;&gt;Not limited to Markdown&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far I have talked about Markdown (and code comments),
but these wrapping styles can be applied
to many other lightweight markup languages as well.
Here's a non-exhaustive list of
other compatible lightweight markup languages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://asciidoc.org/&quot; class=&quot;link link-external&quot;&gt;AsciiDoc&lt;/a&gt;,
&amp;quot;a text document format for writing notes, documentation, articles, books,
ebooks, slideshows, web pages, man pages and blogs.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://orgmode.org/&quot; class=&quot;link link-external&quot;&gt;Org mode&lt;/a&gt;,
&amp;quot;a GNU Emacs major mode for convenient plain text markup –
and much more.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docutils.sourceforge.io/rst.html&quot; class=&quot;link link-external&quot;&gt;reStructuredText&lt;/a&gt;,
&amp;quot;an easy-to-read, what-you-see-is-what-you-get plaintext markup syntax
and parser system.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Help:Wikitext&quot; class=&quot;link link-external&quot;&gt;Wikitext&lt;/a&gt;,
&amp;quot;consists of the syntax and keywords
used by the MediaWiki software to format a page.&amp;quot;
The best known MediaWiki site (or &amp;quot;software&amp;quot;) is Wikipedia.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above list is adapted from a similar list on the website of
&lt;a href=&quot;https://sembr.org/&quot; class=&quot;link link-external&quot;&gt;Semantic Line Breaks specification&lt;/a&gt;.
The descriptions are copied from the linked pages.&lt;/p&gt;
&lt;h2 id=&quot;the-4-1-wrapping-styles&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-4-1-wrapping-styles&quot;&gt;The 4 + 1 wrapping styles&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's use the following examples
for comparing the different wrapping styles:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The following paragraph from my blog post
&lt;a href=&quot;https://mtsknn.fi/blog/switch-statements-default-doesnt-have-to-be-the-last-case/&quot; class=&quot;link&quot;&gt;&lt;em&gt;Switch statements: &lt;code&gt;default&lt;/code&gt; doesn't have to be the last case&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;After some thought,
it's actually logical to present the game states (&lt;code&gt;switch&lt;/code&gt; cases)
in the order they have been presented:
&amp;quot;waiting to start,&amp;quot;
&amp;quot;playing&amp;quot;
and &amp;quot;dead.&amp;quot;
That's the natural flow of the game states.
The initial game state is &amp;quot;waiting to start,&amp;quot;
so the most logical position for the &lt;code&gt;default&lt;/code&gt; case
is at the beginning.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The following code comment from my
&lt;a href=&quot;https://github.com/mtsknn/AutoHotkey/blob/b39db08/scripts/special_characters.ahk&quot; class=&quot;link link-external&quot;&gt;AutoHotkey script &lt;code&gt;special_characters.ahk&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No need to define separate hotstrings for uppercase letters
because hotstrings are &amp;quot;case-conforming&amp;quot; by default.
Applies to the &lt;code&gt;;aring&lt;/code&gt; → &lt;code&gt;å&lt;/code&gt; hotstring as well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The Markdown paragraph is rendered in the same way with all wrapping styles.
The difference is in how the text looks like in the source code.&lt;/p&gt;
&lt;p&gt;(Code comments are often read only in the source code,
so the above doesn't apply as well.)&lt;/p&gt;
&lt;h3 id=&quot;a-paragraph-per-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#a-paragraph-per-line&quot;&gt;A paragraph per line&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Readability&lt;/h4&gt;
&lt;p&gt;Possibly annoying to read
because lines are so long.
Depends on the window width of the IDE
and whether long lines are hard wrapped automatically.&lt;/p&gt;
&lt;h4&gt;Maintainability&lt;/h4&gt;
&lt;p&gt;Paragraphs are easy to identify,
so the style is easy to follow.&lt;/p&gt;
&lt;p&gt;On the other hand,
editing long lines is cumbersome
as you can't e.g. rearrange the sentences of a paragraph by rearranging lines.&lt;/p&gt;
&lt;h4&gt;Diffability&lt;/h4&gt;
&lt;p&gt;Git diffs are noisy,
especially for long paragraphs,
because changing a single word highlights the whole paragraph.
It looks like the whole paragraph has been touched,
and it kind of has because it's on a single line,
so you have to manually check what has actually changed.&lt;/p&gt;
&lt;h4&gt;Markdown example&lt;/h4&gt;
&lt;p&gt;The line is very long (329 characters),
causing a horizontal scroll bar to appear.&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;After some thought, it's actually logical to present the game states (&lt;span class=&quot;token code-snippet code keyword&quot;&gt;`switch`&lt;/span&gt; cases) in the order they have been presented: &quot;waiting to start,&quot; &quot;playing&quot; and &quot;dead.&quot; That's the natural flow of the game states. The initial game state is &quot;waiting to start,&quot; so the most logical position for the &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`default`&lt;/span&gt; case is at the beginning.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Code comment example&lt;/h4&gt;
&lt;p&gt;Same here:
a wild horizontal scroll bar appears!&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-clojure bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; No need to define separate hotstrings for uppercase letters because hotstrings are &quot;case-conforming&quot; by default. Applies to the `;aring` → `å` hotstring as well.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-sentence-per-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#a-sentence-per-line&quot;&gt;A sentence per line&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;Readability&lt;/h4&gt;
&lt;p&gt;Better than in the &amp;quot;a paragraph per line&amp;quot; style.
The problem is that a sentence can contain multiple points and ideas,
so you have to check the whole line to see what's it about.&lt;/p&gt;
&lt;p&gt;Long sentences might be annoying to read
if they are not automatically hard wrapped by the IDE.&lt;/p&gt;
&lt;h4&gt;Maintainability&lt;/h4&gt;
&lt;p&gt;Sentences are easy to identify,
so the style is easy to follow.&lt;/p&gt;
&lt;p&gt;Sentences can be easily rearranged
by rearranging lines.&lt;/p&gt;
&lt;p&gt;Might encourage not-too-long sentences
because very long lines stand out.&lt;/p&gt;
&lt;h4&gt;Diffability&lt;/h4&gt;
&lt;p&gt;Better than in the &amp;quot;a paragraph per line&amp;quot; style.
Some lines might still be too long,
making diffs noisy.&lt;/p&gt;
&lt;h4&gt;Markdown example&lt;/h4&gt;
&lt;p&gt;I like this better than putting the whole paragraph on the same line.
The first and last lines are still too long, though.&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;After some thought, it's actually logical to present the game states (&lt;span class=&quot;token code-snippet code keyword&quot;&gt;`switch`&lt;/span&gt; cases) in the order they have been presented: &quot;waiting to start,&quot; &quot;playing&quot; and &quot;dead.&quot;
That's the natural flow of the game states.
The initial game state is &quot;waiting to start,&quot; so the most logical position for the &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`default`&lt;/span&gt; case is at the beginning.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Code comment example&lt;/h4&gt;
&lt;p&gt;Same here:
this is better,
but the first line is too long.&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-clojure bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; No need to define separate hotstrings for uppercase letters because hotstrings are &quot;case-conforming&quot; by default.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;; Applies to the `;aring` → `å` hotstring as well.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;hard-wrapping-at-eg-80-characters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#hard-wrapping-at-eg-80-characters&quot;&gt;Hard wrapping at e.g. 80 characters&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hard wrapping used to be my favorite wrapping style.
My rationale back then:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are hard wrapping your code at &lt;em&gt;n&lt;/em&gt; characters,
it's logical to hard wrap code comments at the same width.
And why not hard wrap Markdown prose as well?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(If you are not hard wrapping your code,
maybe you should.
Configure &lt;a href=&quot;https://prettier.io/&quot; class=&quot;link link-external&quot;&gt;Prettier&lt;/a&gt; or a similar tool
and you don't have to think about it manually.)&lt;/p&gt;
&lt;h4&gt;Readability&lt;/h4&gt;
&lt;p&gt;Hard wrapped text often looks neat on the surface
as the text has a uniform width.
There are no horizontal scroll bars
or automatic hard wrapping done by the IDE,
unless there are very long words (like links)
or the window is very narrow.&lt;/p&gt;
&lt;p&gt;On the other hand,
the text is often annoying to read
because hard wrapping doesn't factor in sentence structures and such.
It's difficult to see where sentences start and end
and what points and ideas the whole paragraph contains.&lt;/p&gt;
&lt;p&gt;Sometimes hard wrapping can break syntax highlighting,
e.g. when a Markdown link spans on two lines like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Here's some intro text, followed by a &lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;link with quite a long text so that it
spans on two lines&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;https://duck.com/&lt;/span&gt;)&lt;/span&gt;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly:
orphan words are annoying,
i.e. single words that end up on their own lines.
Can be seen in the code comment example below.
Also see
&lt;a href=&quot;https://en.wikipedia.org/wiki/Widows_and_orphans&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Widows and orphans&lt;/em&gt; on Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Maintainability&lt;/h4&gt;
&lt;p&gt;Very cumbersome to maintain manually.
Change a single word in the middle of a paragraph,
and you might have to adjust the wrapping of several lines.&lt;/p&gt;
&lt;p&gt;On the other hand,
can be done easily with certain tools.
For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/&quot; class=&quot;link link-external&quot;&gt;Prettier&lt;/a&gt;,
works at least with Markdown prose
(not sure about code comments).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=stkb.rewrap&quot; class=&quot;link link-external&quot;&gt;Rewrap extension for VS Code.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=stkb.Rewrap-18980&quot; class=&quot;link link-external&quot;&gt;Rewrap extension for Visual Studio.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The downside of using tools is that
you also have to get your teammates to
install, configure and use them.&lt;/p&gt;
&lt;h4&gt;Diffability&lt;/h4&gt;
&lt;p&gt;Often abysmal.
Change a single word in the middle of a paragraph,
and you might have to adjust the wrapping of several lines.
This makes diffs very noisy.&lt;/p&gt;
&lt;h4&gt;Markdown example&lt;/h4&gt;
&lt;p&gt;Looks nice on the surface,
but is not very nice to read.
The two words inside the parentheses
unfortunaly end up on different lines.&lt;/p&gt;
&lt;p&gt;Looking at the left side of the code block
(the first words of the lines)
doesn't make much sense:
&amp;quot;After... cases... dead... waiting to start... the beginning.&amp;quot;&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;After some thought, it's actually logical to present the game states (&lt;span class=&quot;token code-snippet code keyword&quot;&gt;`switch`&lt;/span&gt;
cases) in the order they have been presented: &quot;waiting to start,&quot; &quot;playing&quot; and
&quot;dead.&quot; That's the natural flow of the game states. The initial game state is
&quot;waiting to start,&quot; so the most logical position for the &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`default`&lt;/span&gt; case is at
the beginning.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Code comment example&lt;/h4&gt;
&lt;p&gt;The last line contains an orphan word.
It looks lonely
and makes the whole comment look unbalanced.&lt;/p&gt;
&lt;p&gt;Looking at the second line only,
the beginning of it doesn't make sense:
&amp;quot;are 'case-conforming' by default.&amp;quot;
What is it talking about?
You need to check the previous line
to see that it's talking about hotstrings.&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-clojure bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; No need to define separate hotstrings for uppercase letters because hotstrings&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;; are &quot;case-conforming&quot; by default. Applies to the `;aring` → `å` hotstring as&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;; well.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;semantic-line-breaks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#semantic-line-breaks&quot;&gt;Semantic line breaks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://sembr.org/&quot; class=&quot;link link-external&quot;&gt;Semantic Line Breaks specification&lt;/a&gt;
is introed like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When writing text with a compatible markup language,
add a line break after each substantial unit of thought.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Semantic line breaks are my favorite!
I have been using them at least since Nov 2020,
i.e. for at least half a year at the time of this writing.&lt;/p&gt;
&lt;h4&gt;Readability&lt;/h4&gt;
&lt;p&gt;Lines tend to be short,
which reduces the amount of horizontal eye movement,
making the text easier to read.&lt;/p&gt;
&lt;p&gt;It's also easy to jump around the text vertically
looking for capital letters,
i.e. where sentences begin and end.&lt;/p&gt;
&lt;h4&gt;Maintainability&lt;/h4&gt;
&lt;p&gt;A single line contains a &amp;quot;substantial unit of thought&amp;quot;
like a clause or an idea.
This makes editing text more powerful
because it's easy to rearrange clauses and ideas
by rearranging lines.
Compare with e.g. hard wrapping:
you can't just rearrange lines,
because the text wouldn't make sense anymore.&lt;/p&gt;
&lt;p&gt;Another benefit,
copied from the specification's FAQ section:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Semantic line breaks make it easier to
identify grammatical mistakes
and find opportunities to simplify and clarify without altering original intent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And yet another,
copied from a comment by Rich Morin
in Brandon Rhodes's blog post
&lt;a href=&quot;https://rhodesmill.org/brandon/2012/one-sentence-per-line/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Semantic Linefeeds&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Another benefit of this technique is that
it gives the author (or editor)
a chance to examine the text in two very different formats:
monospace with line breaks
and proportional without.
This helps greatly in finding errors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One drawback is that
it might be difficult to decide/learn
what is a semantic line break,
or what is a &amp;quot;substantial unit of thought.&amp;quot;
Thus, different people might wrap the same text differently.&lt;/p&gt;
&lt;p&gt;If you are working in a team,
it might lead to slight inconsistencies.&lt;/p&gt;
&lt;p&gt;If you are working solo,
it's not a problem.
You'll quickly come up with your own style.&lt;/p&gt;
&lt;h4&gt;Diffability&lt;/h4&gt;
&lt;p&gt;Excellent.
Small changes tend to produce clean diffs.&lt;/p&gt;
&lt;p&gt;For a visual example,
see Brandon Rhodes's blog post
&lt;a href=&quot;https://rhodesmill.org/brandon/2012/one-sentence-per-line/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Semantic Linefeeds&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Markdown example&lt;/h4&gt;
&lt;p&gt;The text looks a bit unbalanced,
but each line contains a single thing.
I'm sure someone else would wrap this code differently,
even if we both used semantic line breaks. :-)&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;After some thought,
it's actually logical
to present the game states (&lt;span class=&quot;token code-snippet code keyword&quot;&gt;`switch`&lt;/span&gt; cases)
in the order they have been presented:
&quot;waiting to start,&quot;
&quot;playing&quot; and
&quot;dead.&quot;
That's the natural flow of the game states.
The initial game state is &quot;waiting to start,&quot;
so the most logical position for the &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`default`&lt;/span&gt; case
is at the beginning.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Code comment example&lt;/h4&gt;
&lt;p&gt;Yay, the orphan word is gone.&lt;/p&gt;
&lt;p&gt;The second line makes sense on its own:
&amp;quot;(because) hotstrings are 'case-conforming' by default.&amp;quot;&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-clojure bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; No need to define separate hotstrings for uppercase letters&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;; because hotstrings are &quot;case-conforming&quot; by default.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;; Applies to the `;aring` → `å` hotstring as well.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;1-chaos&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#1-chaos&quot;&gt;+1: Chaos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you don't deliberately choose a specific style
for wrapping code comments and prose,
you'll eventually have lots of inconsistencies.
Inconsistencies lead to chaos,
and chaos means poor readability and maintainability.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hat tip to the
&lt;a href=&quot;https://sembr.org/&quot; class=&quot;link link-external&quot;&gt;Semantic Line Breaks specification&lt;/a&gt;
for teaching me a better alternative to hard wrapping.
My earlier blog post
&lt;a href=&quot;https://mtsknn.fi/blog/rfc-2119-in-a-nutshell/&quot; class=&quot;link&quot;&gt;&lt;em&gt;RFC 2119 in a nutshell&lt;/em&gt;&lt;/a&gt;
might be helpful for interpreting the specification.&lt;/p&gt;
&lt;p&gt;Brandon Rhodes's blog post
&lt;a href=&quot;https://rhodesmill.org/brandon/2012/one-sentence-per-line/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Semantic Linefeeds&lt;/em&gt;&lt;/a&gt;
from 2012
covers the same general idea as semantic line breaks.
It has an example of the diffing benefits
and musings on the history of semantic line breaks.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/react-two-way-data-binding/</id><title>Two-way data binding in React</title><link href="https://mtsknn.fi/blog/react-two-way-data-binding/" /><published>2021-05-08T12:00:00+03:00</published><updated>2021-05-08T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;Normally you would use one-way data binding in React apps:
parent components own data and pass it to children.
You can mimic two-way data binding with a custom hook.&lt;/p&gt;
&lt;h2 id=&quot;one-way-data-binding&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#one-way-data-binding&quot;&gt;One-way data binding&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;React uses one-way data binding
for controlled components:
a parent passes to its child
the current state value
and a function to update the value.
For example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setValue&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'John'&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 function-variable function&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;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 function&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&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 function-variable function&quot;&gt;reset&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&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 punctuation&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&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;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;update&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Hello &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;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;reset&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;Reset&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way the input element (the child) never mutates the state.
Instead it calls the &lt;code&gt;update&lt;/code&gt; function (via the &lt;code&gt;onChange&lt;/code&gt; event),
so that the &lt;em&gt;parent&lt;/em&gt; can update the state
and pass the new value to the input element.&lt;/p&gt;
&lt;p&gt;So far this is very basic stuff.&lt;/p&gt;
&lt;p&gt;AngularJS 1 used to have two-way data binding:
a parent passes only the state to its child,
and the child can directly mutate the state!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the parent updates the state,
the child will receive the new value.&lt;/li&gt;
&lt;li&gt;If the child updates the state,
the parent will receive the new value.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the parent receives a new value,
it can't know where the new value is coming from,
and it can't prevent the child from updating the value.&lt;/p&gt;
&lt;p&gt;Two-way data binding is nowadays considered a bad practice
because it can easily lead to
unpredictability (can't know what's changing state)
and poor performance.
Possibly for other reasons too.&lt;/p&gt;
&lt;h2 id=&quot;two-way-data-binding&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#two-way-data-binding&quot;&gt;Two-way data binding&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On the upside,
two-way data binding makes code cleaner
as you don't have to manually deal with event listeners and stuff.
Just pass a state to a child and you're done.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sandroroth.com/blog/react-two-way-data-binding&quot; class=&quot;link link-external&quot;&gt;Sandro Roth's blog post &lt;em&gt;Two-way Data Binding in React&lt;/em&gt;&lt;/a&gt;
shows how you can mimic two-way data binding in React by writing a custom hook.
Like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setValue&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialValue&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 function-variable function&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;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 function&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&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 literal-property property&quot;&gt;model&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; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; update &lt;span class=&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;setModel&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; setValue&lt;span class=&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 function&quot;&gt;App&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setModel &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'John'&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 function-variable function&quot;&gt;reset&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&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 punctuation&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;input&lt;/span&gt; &lt;span class=&quot;token spread&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;reset&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&gt;Reset&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how we are passing (via spreading) only a &amp;quot;model&amp;quot; to the input element.
The model contains the current value
and a function to update the value from the child.&lt;/p&gt;
&lt;p&gt;This is ultimately still one-way data binding –
the parent is still the single source of truth for the state –
but it looks cleaner
and allows reusage of the logic contained in the &lt;code&gt;useModel&lt;/code&gt; hook.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sandroroth.com/blog/react-two-way-data-binding&quot; class=&quot;link link-external&quot;&gt;Check out Sandro's article for more details!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(Also thanks to Sandro for our email exchange over this topic. 😊)&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/site-specific-components/</id><title>Site-specific components in a (React) multi-site</title><link href="https://mtsknn.fi/blog/site-specific-components/" /><published>2021-05-01T12:00:00+03:00</published><updated>2021-08-17T12:00:00+03:00</updated><category term="Clean code"></category><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;A multi-site React project has likely two kinds of components:
common components and site-specific components.
There are a few ways to handle site-specific logic in common components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Common components are used by two or more sites
and reside e.g. under the &lt;code&gt;src/common/&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Site-specific components are used only by one site
and reside e.g. under the folders &lt;code&gt;src/site-a/&lt;/code&gt;, &lt;code&gt;src/site-b/&lt;/code&gt; and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An example of a common component is &lt;code&gt;Link&lt;/code&gt;:
a hyperlink with certain styles and logic,
used on all sites for most links.&lt;/p&gt;
&lt;p&gt;Let's say that Site A,
and only that site,
requires some extra logic in the &lt;code&gt;Link&lt;/code&gt; component.
What are my options?
Let's think:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add the extra logic to the common &lt;code&gt;Link&lt;/code&gt; component.
This would be messy,
because the common component would then have site-specific logic in it.&lt;/li&gt;
&lt;li&gt;Create an entirely separate, site-specific &lt;code&gt;Link&lt;/code&gt; component for Site A.
I don't like this option
because the common and site-specific &lt;code&gt;Link&lt;/code&gt; components would have lots of duplicate code.
Links are very common,
so any future changes would have to be made to two components.&lt;/li&gt;
&lt;li&gt;Create a &amp;quot;child component&amp;quot; for Site A,
so that the site-specific component
ultimately renders the common &lt;code&gt;Link&lt;/code&gt; component.
This would be nice,
but the problem would be that
developers would need to remember to import the site-specific component when working on Site A's code,
and to import the common component when working on the other sites' codes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I eventually found a way to avoid the problem in the third option!
Behold:
&lt;a href=&quot;/blog/eslint-import-restrictions/&quot; class=&quot;link&quot;&gt;Using ESLint to restrict where files can be imported from&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/eslint-import-restrictions/</id><title>Using ESLint to restrict where files can be imported from</title><link href="https://mtsknn.fi/blog/eslint-import-restrictions/" /><published>2021-05-01T12:00:00+03:00</published><updated>2021-05-01T12:00:00+03:00</updated><category term="ESLint"></category><category term="JavaScript"></category><content type="html">&lt;p&gt;There's an ESLint rule to prevent importing certain files in certain folders.
I needed this in a multi-site project
to prevent importing site-specific components in other sites' folders.&lt;/p&gt;
&lt;p&gt;I'm talking about the
&lt;a href=&quot;https://github.com/benmosher/eslint-plugin-import/blob/HEAD/docs/rules/no-restricted-paths.md&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;no-restricted-paths&lt;/code&gt; ESLint rule&lt;/a&gt;,
provided by the &lt;a href=&quot;https://github.com/benmosher/eslint-plugin-import&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;eslint-plugin-import&lt;/code&gt; plugin&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Some projects contain files which are not always meant to be executed in the same environment.
For example consider a web application that contains specific code for the server and some specific code for the browser/client.
In this case you don't want to import server-only files in your client code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my case I needed the rule to make using site-specific components more convenient.
Context: &lt;a href=&quot;/blog/site-specific-components/&quot; class=&quot;link&quot;&gt;Site-specific components in a multi-site (React) project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's what I added to the project's ESLint config
to solve the problem discussed in the linked blog post:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;'import/no-restricted-paths'&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;'error'&lt;/span&gt;&lt;span class=&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;zones&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;target&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'src/site-a/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'src/common/Link.js'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Import the site-specific Link component instead.'&lt;/span&gt;&lt;span class=&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 punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The config makes ESLint throw an error
if &lt;code&gt;src/common/Link.js&lt;/code&gt; is imported in any file under &lt;code&gt;src/site-a/&lt;/code&gt;.
Plus ESLint will show the custom message
so no one has to guess why importing the common &lt;code&gt;Link&lt;/code&gt; component fails.
Excellent!&lt;/p&gt;
&lt;p&gt;To prevent importing certain npm packages,
you could use
&lt;a href=&quot;https://eslint.org/docs/rules/no-restricted-imports&quot; class=&quot;link link-external&quot;&gt;ESLint's native rule &lt;code&gt;no-restricted-imports&lt;/code&gt;&lt;/a&gt;.
A useful example case is
if you want developers to import your own &lt;code&gt;Link&lt;/code&gt; component
instead of React Router's &lt;code&gt;Link&lt;/code&gt; component.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/logitech-brio/</id><title>My new webcam: Logitech BRIO</title><link href="https://mtsknn.fi/blog/logitech-brio/" /><published>2021-04-24T12:00:00+03:00</published><updated>2021-04-24T12:00:00+03:00</updated><category term="Battlestation"></category><content type="html">&lt;p&gt;Maybe a bit of an overkill,
but much more convenient than using my iPad as a webcam
or my laptop's integrated webcam.&lt;/p&gt;
&lt;h2 id=&quot;my-previous-webcams&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#my-previous-webcams&quot;&gt;My previous webcams&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have previously used my iPad mini as a webcam
via the &lt;a href=&quot;https://www.elgato.com/en/epoccam&quot; class=&quot;link link-external&quot;&gt;EpocCam app&lt;/a&gt;.
It has worked well,
but it's always a hassle to set up a stand for the iPad.
The iPad is also blocking a big portion of my monitor.&lt;/p&gt;
&lt;p&gt;My laptop has an integrated webcam,
but it's too far to the side
when using an external monitor,
so I haven't used it.
I suspect it wouldn't even have good quality.&lt;/p&gt;
&lt;h2 id=&quot;logitech-brio&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#logitech-brio&quot;&gt;Logitech BRIO&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some months ago I bought a &lt;a href=&quot;/blog/my-new-microphone-rode-procaster/&quot; class=&quot;link&quot;&gt;new microphone&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This week I bought a new webcam:
&lt;a href=&quot;https://www.logitech.com/en-us/products/webcams/brio-4k-hdr-webcam.html&quot; class=&quot;link link-external&quot;&gt;Logitech BRIO&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I already used the BRIO in one Teams meeting,
and it worked well.&lt;/p&gt;
&lt;p&gt;I like that the BRIO just stays on top of my monitor.
There's no setting it up and opening an app
every time I want to use it,
unlike when using iPad via EpocCam.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/frequency-illusion/</id><title>Frequency illusion</title><link href="https://mtsknn.fi/blog/frequency-illusion/" /><published>2021-04-24T12:00:00+03:00</published><updated>2021-04-24T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;That cool thing you just heard about –
is it suddenly gaining popularity,
or are you just noticing the topic more?&lt;/p&gt;
&lt;p&gt;After learning about a new topic,
it sometimes seems to quickly surge in popularity.
Like &amp;quot;wow, this topic is nowadays being covered &lt;em&gt;everywhere&lt;/em&gt;&amp;quot;
or &amp;quot;awareness of this topic is clearly increasing, nice.&amp;quot;&lt;/p&gt;
&lt;p&gt;That's possible.
Or, it's also possible that you are just noticing the topic more.&lt;/p&gt;
&lt;p&gt;Here's what Wikipedia tells us about
&lt;a href=&quot;https://en.wikipedia.org/wiki/Frequency_illusion&quot; class=&quot;link link-external&quot;&gt;frequency illusion&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Frequency illusion&lt;/strong&gt;,
also known as the &lt;strong&gt;Baader–Meinhof phenomenon&lt;/strong&gt;,
is a cognitive bias in which,
after noticing something for the first time,
there is a tendency to notice it more often,
leading someone to believe that it has a high frequency (a form of selection bias).
It occurs when increased awareness of something
creates the illusion that it is appearing more often.
Put plainly,
the frequency illusion is when
&amp;quot;a concept or thing you just found out about
suddenly seems to crop up everywhere.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had been looking for a term for this phenomenon.
Now let's see if I start to notice lots of coverage of the frequency illusion.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/css-vertical-margin-auto/</id><title>\*Vertical* centering in CSS with `margin: auto`</title><link href="https://mtsknn.fi/blog/css-vertical-margin-auto/" /><published>2021-04-24T12:00:00+03:00</published><updated>2021-04-24T12:00:00+03:00</updated><category term="CSS"></category><category term="CSS for JS Devs course"></category><content type="html">&lt;p&gt;&lt;code&gt;margin: auto&lt;/code&gt; is not only for horizontal centering.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;margin: auto&lt;/code&gt; normally centers a block element only horizontally.
To achieve vertical centering,
it's common to reach for e.g. flexbox.&lt;/p&gt;
&lt;p&gt;Turns out that &lt;code&gt;margin: auto&lt;/code&gt; can in some cases center vertically as well.
The element must also have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;position: absolute&lt;/code&gt; or &lt;code&gt;position: fixed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;top: 0&lt;/code&gt; and &lt;code&gt;bottom: 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;an explicit height (e.g. &lt;code&gt;height: 200px&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This can be very useful for modals.&lt;/p&gt;
&lt;p&gt;Note that for only vertical centering,
only &lt;code&gt;margin-top&lt;/code&gt; and &lt;code&gt;margin-bottom&lt;/code&gt; need to be set to &lt;code&gt;auto&lt;/code&gt;;
&lt;code&gt;margin-right&lt;/code&gt; and &lt;code&gt;margin-left&lt;/code&gt; can be anything.
This is similar to horizontal centering:
only &lt;code&gt;margin-right&lt;/code&gt; and &lt;code&gt;margin-left&lt;/code&gt; need to be set to &lt;code&gt;auto&lt;/code&gt;;
&lt;code&gt;margin-top&lt;/code&gt; and &lt;code&gt;margin-bottom&lt;/code&gt; can be anything.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgzgpgNhDGAuEAmIBcIB0ALeBbKIANCAGYCWMYaA2qAHYCGuEamO+RIsA9nYn6wA8YeAE8YAPgA6dAASykZAG6zgM+fIBGDWAGsA5gCduAVzpJUCiBAAONsnV0BudRqwQy+nJYCMABj8bAA8XOQ0AdzIkeCxfAODQjVkbbjAyeDJeSwZNMG4oE0RQ13kAegAqWSUIQwzYBihZWAg+God9WXLSktl4bhtLP0SNTW54PtxB4flcBkN9BwBaPoHZBkLuadlZ+aXR8e5JtY3isLLKrG5DMgAvXngGppbEa7oOrp7rr3gpnpgSH6yIY9HYLOiLL7eY59Lagpb-QHrGGuAC+MkEpRE4gg0jogkUSgkGIJEk4kBgCEydCo6AATH5UD4fCAUQBdFFAA&quot; class=&quot;link link-external&quot;&gt;See an example on flems.io.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I learned this from Josh W Comeau's
&lt;a href=&quot;https://css-for-js.dev/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;CSS for JavaScript developers&lt;/em&gt; course&lt;/a&gt;
(Module 2).&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/breaking-css-position-fixed/</id><title>`position: fixed` breaks if any of its ancestors uses `transform`</title><link href="https://mtsknn.fi/blog/breaking-css-position-fixed/" /><published>2021-04-24T12:00:00+03:00</published><updated>2021-04-24T12:00:00+03:00</updated><category term="CSS"></category><category term="CSS for JS Devs course"></category><content type="html">&lt;p&gt;Or &lt;code&gt;perspective&lt;/code&gt; or &lt;code&gt;filter&lt;/code&gt;.
This can easily cause confusing bugs.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;position: fixed&lt;/code&gt; works mostly the same way as &lt;code&gt;position: absolute&lt;/code&gt; does.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;position: absolute&lt;/code&gt; is positioned relative to its closest positioned ancestor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;position: fixed&lt;/code&gt; is positioned relative to the viewport.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However,
in the case of &lt;code&gt;position: fixed&lt;/code&gt;,
if any of the element's ancestors (i.e. parent or any of the grandparents)
has a &lt;code&gt;transform&lt;/code&gt; property set to something else than &lt;code&gt;none&lt;/code&gt;,
the element's positioning &amp;quot;breaks.&amp;quot;
The fixed element is then positioned relative to that ancestor,
i.e. &lt;code&gt;position: fixed&lt;/code&gt; behaves like &lt;code&gt;position: absolute&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This can easily cause confusing bugs.&lt;/p&gt;
&lt;p&gt;I learned this from Josh W Comeau's
&lt;a href=&quot;https://css-for-js.dev/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;CSS for JavaScript developers&lt;/em&gt; course&lt;/a&gt;
(Module 2).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed&quot; class=&quot;link link-external&quot;&gt;MDN's documentation on &lt;code&gt;position: fixed&lt;/code&gt;&lt;/a&gt;
mentions that
the &lt;code&gt;perspective&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; properties also break &lt;code&gt;position: fixed&lt;/code&gt;,
but
&amp;quot;there are browser inconsistencies with &lt;code&gt;perspective&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt;
contributing to containing block formation.&amp;quot;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-fn-length/</id><title>JavaScript functions have a `length` property</title><link href="https://mtsknn.fi/blog/js-fn-length/" /><published>2021-04-17T12:00:00+03:00</published><updated>2022-08-14T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;A bit exotic, but can be useful for currying.&lt;/p&gt;
&lt;h2 id=&quot;functionlength&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#functionlength&quot;&gt;&lt;code&gt;Function.length&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;length&lt;/code&gt; property of a function
returns the number of required arguments:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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 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;length                    &lt;span class=&quot;token comment&quot;&gt;//=&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 parameter&quot;&gt;a&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 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;length                   &lt;span class=&quot;token comment&quot;&gt;//=&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 parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&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;length                &lt;span class=&quot;token comment&quot;&gt;//=&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 parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&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 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;length             &lt;span class=&quot;token comment&quot;&gt;//=&gt; 3&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'default'&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 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;length &lt;span class=&quot;token comment&quot;&gt;//=&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 parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&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 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;length          &lt;span class=&quot;token comment&quot;&gt;//=&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 parameter&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&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 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;length             &lt;span class=&quot;token comment&quot;&gt;//=&gt; 0&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I learned this from
a &lt;a href=&quot;https://twitter.com/mikaelainalem/status/1348160028772102146&quot; class=&quot;link link-external&quot;&gt;tweet by Mikael Ainalem&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See also
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Function.length&lt;/code&gt; on MDN&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;trust-issues&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#trust-issues&quot;&gt;Trust issues&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Robin Pokorny says that
&lt;a href=&quot;https://robinpokorny.com/blog/function-length-property-is-not-to-be-trusted/&quot; class=&quot;link link-external&quot;&gt;the &lt;code&gt;length&lt;/code&gt; property is not to be trusted&lt;/a&gt;
because it can be overridden:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
fn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token comment&quot;&gt;//=&gt; 2&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'length'&lt;/span&gt;&lt;span class=&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;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

fn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token comment&quot;&gt;//=&gt; 3&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But don't do that. 😄&lt;/p&gt;
&lt;h2 id=&quot;example-currying&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-currying&quot;&gt;Example: currying&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One practical use of &lt;code&gt;Function.length&lt;/code&gt;
is to use it to create a currying function:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;curry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&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;
  fn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length
    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn&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;args&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 function-variable function&quot;&gt;mul&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&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; a &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; c

&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&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 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 number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&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 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 number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&lt;span class=&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 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 number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mul&lt;span class=&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 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 number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Source of the &lt;code&gt;curry&lt;/code&gt; function:
&lt;a href=&quot;https://twitter.com/babakness/status/1348683843163734016&quot; class=&quot;link link-external&quot;&gt;Babak's reply to Mikael's tweet&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/css-height-and-width-logics/</id><title>Different logics behind heights and widths in CSS</title><link href="https://mtsknn.fi/blog/css-height-and-width-logics/" /><published>2021-04-17T12:00:00+03:00</published><updated>2021-04-17T12:00:00+03:00</updated><category term="CSS"></category><category term="CSS for JS Devs course"></category><content type="html">&lt;p&gt;&lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; work somewhat differently in CSS.
&lt;code&gt;height&lt;/code&gt; looks &amp;quot;down&amp;quot; the tree
whereas &lt;code&gt;width&lt;/code&gt; looks &amp;quot;up&amp;quot; the tree.&lt;/p&gt;
&lt;p&gt;Full quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;height&lt;/code&gt; tends to look &amp;quot;down&amp;quot; the tree,
to determine its size based on the natural size of its contents,
while &lt;code&gt;width&lt;/code&gt; tends to look &amp;quot;up&amp;quot; the tree,
basing its size on the space made available by the parent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The quote is from Josh W Comeau's
&lt;a href=&quot;https://css-for-js.dev/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;CSS for JavaScript developers&lt;/em&gt; course&lt;/a&gt;
(Module 1).&lt;/p&gt;
&lt;p&gt;I don't know if the quote makes sense on its own (without more context).
But I thought it describes the difference between &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt;
very clearly yet succinctly,
so I wanted to share it here.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/css-block-vs-inline/</id><title>Block vs inline directions in CSS</title><link href="https://mtsknn.fi/blog/css-block-vs-inline/" /><published>2021-04-10T12:00:00+03:00</published><updated>2021-04-10T12:00:00+03:00</updated><category term="CSS"></category><category term="CSS for JS Devs course"></category><content type="html">&lt;p&gt;Block elements stack on top of each other.
Inline elements are placed side by side.&lt;/p&gt;
&lt;h2 id=&quot;web-pages-vs-paper-documents&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#web-pages-vs-paper-documents&quot;&gt;Web pages vs paper documents&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web pages are like paper documents.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Individual words are &lt;em&gt;inline&lt;/em&gt; and placed side by side,
from left to right (or right to left in some languages).&lt;/li&gt;
&lt;li&gt;Some words are combined into &lt;em&gt;blocks&lt;/em&gt;
(e.g. headings and paragraphs)
that stack on top of each other,
from top to bottom (or bottom to top in some obscure languages).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, that's the two directions of CSS: block and inline.
And that's how &lt;code&gt;display: block&lt;/code&gt; and &lt;code&gt;display: inline&lt;/code&gt; work too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Block elements (&lt;code&gt;display: block&lt;/code&gt;) take the full available width by default
so that they stack on top of each other.
Think of e.g. headings, paragraphs and &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements.&lt;/li&gt;
&lt;li&gt;Inline elements (&lt;code&gt;display: inline&lt;/code&gt;) are placed side by side.
Think of e.g. individual words and &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is very basic,
but explaining block and inline directions
by comparing a web page to a regular paper document
was somehow eye-opening to me.
I like this &lt;em&gt;mental model&lt;/em&gt;
that I learned from Josh W Comeau's
&lt;a href=&quot;https://css-for-js.dev/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;CSS for JavaScript developers&lt;/em&gt; course&lt;/a&gt;
(Module 1).&lt;/p&gt;
&lt;h2 id=&quot;logical-properties&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#logical-properties&quot;&gt;Logical properties&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Understanding the two directions is also essential for understanding
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties&quot; class=&quot;link link-external&quot;&gt;logical properties in CSS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example,
when working with right-to-left (RTL) languages,
you might want to use
&lt;code&gt;margin-inline-start&lt;/code&gt; and &lt;code&gt;margin-inline-end&lt;/code&gt;
instead of
&lt;code&gt;margin-left&lt;/code&gt; and &lt;code&gt;margin-right&lt;/code&gt;.
The latter properties would be in reverse or &amp;quot;wrong&amp;quot; order
when working with RTL languages.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/updating-react-context/</id><title>Updating React context outside of a component</title><link href="https://mtsknn.fi/blog/updating-react-context/" /><published>2021-04-03T12:00:00+03:00</published><updated>2021-04-03T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><category term="Testing"></category><content type="html">&lt;p&gt;React context is normally updated inside the React app.
Here's a hacky way how I circumvented that restriction in a test file.&lt;/p&gt;
&lt;h2 id=&quot;example-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-problem&quot;&gt;Example problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's say I have a React component called &lt;code&gt;MyComponent&lt;/code&gt;
which uses a React context called &lt;code&gt;MyContext&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When the value of the context changes,
the component does something,
e.g. makes an Adobe Analytics tracking call:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyComponent&lt;/span&gt;&lt;span class=&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; myContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&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;
    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_satellite&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;track&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myContext&lt;span class=&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;myContext&lt;span class=&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 keyword&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then I want to write unit tests for that...
But how can I do that
since React contexts can't be easily updated outside of React components?&lt;/p&gt;
&lt;h2 id=&quot;hacky-workaround&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#hacky-workaround&quot;&gt;Hacky workaround&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I realized that in the test file,
I can pass an empty object for the wrapper component (&lt;code&gt;App&lt;/code&gt; in this case)
as a prop (named &lt;code&gt;contextUpdater&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Inside &lt;code&gt;App&lt;/code&gt;,
I can store a reference to the context value setter function (&lt;code&gt;setValue&lt;/code&gt; in this case)
under the given prop object.&lt;/p&gt;
&lt;p&gt;Then, in a test case,
I can call &lt;code&gt;contextUpdater.setValue&lt;/code&gt; –
outside of the component!&lt;/p&gt;
&lt;p&gt;Like so:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* MyComponent.test.js */&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'MyComponent'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; contextUpdater &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&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setValue&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'initial value'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// This hack allows us to update the context value outside of the component&lt;/span&gt;
    contextUpdater&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;setValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; setValue

    &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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MyContext.Provider&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation 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;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setValue&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 class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;MyComponent&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 plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;MyContext.Provider&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 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;beforeEach&lt;/span&gt;&lt;span class=&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;
    global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_satellite &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;track&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&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 function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'makes a tracking call when MyContext changes'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contextUpdater &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 function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;contextUpdater&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;contextUpdater&lt;span class=&quot;token punctuation&quot;&gt;}&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 punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_satellite&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;track&lt;span class=&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;toHaveBeenCalledTimes&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 function&quot;&gt;act&lt;/span&gt;&lt;span class=&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; contextUpdater&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'new 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 function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_satellite&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;track&lt;span class=&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;toHaveBeenCalledTimes&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 function&quot;&gt;act&lt;/span&gt;&lt;span class=&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; contextUpdater&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'third 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 function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_satellite&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;track&lt;span class=&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;toHaveBeenCalledTimes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works!
IQ 200!
Proud moment of the week.&lt;/p&gt;
&lt;h2 id=&quot;too-hacky&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#too-hacky&quot;&gt;Too hacky?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So yeah,
actually this feels very hacky,
probably because this &lt;em&gt;is&lt;/em&gt; hacky.&lt;/p&gt;
&lt;p&gt;Another question is whether the test is too implementation-specific.
On the other hand,
&lt;code&gt;MyComponent&lt;/code&gt; directly depends on &lt;code&gt;MyContext&lt;/code&gt;,
so I'm not sure.&lt;/p&gt;
&lt;p&gt;Anyway,
the test passes,
so I think this is good enough for now.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/excel-durations/</id><title>Excel stores time durations as days</title><link href="https://mtsknn.fi/blog/excel-durations/" /><published>2021-04-03T12:00:00+03:00</published><updated>2021-04-03T12:00:00+03:00</updated><category term="Excel"></category><content type="html">&lt;p&gt;For example, 6 hours is stored as 0.25 days.
To format a duration as &lt;code&gt;hh:mm:ss.000&lt;/code&gt;,
first convert the duration to days.&lt;/p&gt;
&lt;h2 id=&quot;example-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-problem&quot;&gt;Example problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A friend of mine consulted me with this problem:
he was copy-pasting a bunch of time durations to Excel
and wanted to calculate their average duration.&lt;/p&gt;
&lt;p&gt;The values were not in Excel-friendly format,
and he didn't want to modify them by hand,
so Excel's &lt;code&gt;AVERAGE&lt;/code&gt; function didn't work out of the box.&lt;/p&gt;
&lt;p&gt;Here's an example of a single time duration:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-text bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;1:39.811
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's one minute, 39 seconds and 811 milliseconds.&lt;/p&gt;
&lt;h2 id=&quot;failed-attempts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#failed-attempts&quot;&gt;Failed attempts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I first tried to change the formatting of the data,
hoping that Excel would correctly identify the data as time durations.
But I couldn't get that to work.&lt;/p&gt;
&lt;p&gt;I then tried to parse the text and pass its parts to the &lt;code&gt;TIME&lt;/code&gt; function
which takes three parameters:
hours, minutes and seconds.
But passing a decimal number (i.e. seconds with milliseconds) as the third parameter
didn't work.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;converting-the-raw-data-to-milliseconds&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#converting-the-raw-data-to-milliseconds&quot;&gt;Converting the raw data to milliseconds&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the end,
I found it easiest to convert the raw data to milliseconds
using Excel's &lt;code&gt;LEFT&lt;/code&gt;, &lt;code&gt;MID&lt;/code&gt; and &lt;code&gt;RIGHT&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;Here's the formula for the B column,
assuming that the original data resides in the A column:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// A1 contains a duration, e.g. &quot;1:39.811&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// B1 contains the duration in milliseconds.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// In this case it would be &quot;99811&quot;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Minutes:&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// the first character from the left.&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Doesn't support 10+ minute durations,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// but that's probably OK with this data.&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;A1&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 operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Seconds:&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// starting from the third character (1-indexed),&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// take two characters in the middle.&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;A1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&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;1000&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Milliseconds:&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// the three rightmost characters.&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;A1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that the B column contains the time durations in milliseconds,
it's easy to calculate the average value:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AVERAGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;B1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;B999&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But how to format the result as a time duration?&lt;/p&gt;
&lt;h3 id=&quot;displaying-milliseconds-as-a-duration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#displaying-milliseconds-as-a-duration&quot;&gt;Displaying milliseconds as a duration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Luckily,
someone had asked
&lt;a href=&quot;https://old.reddit.com/r/excel/comments/5txvud/convert_milliseconds_to_hhmmss000/&quot; class=&quot;link link-external&quot;&gt;&amp;quot;[How to] convert milliseconds to hh:mm:ss.000&amp;quot; on Reddit&lt;/a&gt;
four years ago,
and someone called &lt;em&gt;sqylogin&lt;/em&gt; had shared this nugget of wisdom
(formatted for clarity):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Excel stores data in days.&lt;/p&gt;
&lt;p&gt;Therefore, 1 millisecond = 1/24/60/60/1,000 = 1/86,400,000.&lt;/p&gt;
&lt;p&gt;To convert 586 milliseconds to an Excel &amp;quot;day,&amp;quot;
divide it by 86.4 million,
and in the resulting cell,
use this custom number format:
&lt;code&gt;HH:MM:SS.000&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ah, so calculating the average time duration is as easy as this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AVERAGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;B1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;B999&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;86400000&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Plus the formatting of the cell displaying the average value needs to be set to this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-text bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;m:ss.000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Egg-cellent!
Now my friend can keep copy-pasting values to the A column,
and the average value will be updated automatically.
He can even hide the B column
since it's only used as an intermediate step to calculate the average value.&lt;/p&gt;
&lt;h2 id=&quot;the-actual-learning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-actual-learning&quot;&gt;The actual learning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Excel is often a very powerful and quick tool to use.
But sometimes it doesn't work like I would want it to,
so I end up fighting it and coming up with hacky solutions like this.&lt;/p&gt;
&lt;p&gt;To be fair,
maybe that applies to all tools
and even programming in general.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/safari-pdf-error/</id><title>&quot;Blocked plug-in&quot; error in Safari when opening a PDF file</title><link href="https://mtsknn.fi/blog/safari-pdf-error/" /><published>2021-03-20T12:00:00+03:00</published><updated>2021-03-20T12:00:00+03:00</updated><category term="Safari"></category><content type="html">&lt;p&gt;Try to add &lt;code&gt;object-src 'self';&lt;/code&gt; to the Content Security Policy.
Then your users don't have to download the file to view it.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was investigating an issue where Safari failed to display a PDF file.
It instead just showed the text &amp;quot;Blocked plug-in.&amp;quot;&lt;/p&gt;
&lt;p&gt;The problem occurred only in desktop Safari.&lt;/p&gt;
&lt;h2 id=&quot;the-fix&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-fix&quot;&gt;The fix&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The user could download the file to view it,
but that would be cumbersome.&lt;/p&gt;
&lt;p&gt;I did some quick googling
but didn't find any good results.&lt;/p&gt;
&lt;p&gt;Then I noticed that
Safari's console showed an error message related to
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&quot; class=&quot;link link-external&quot;&gt;Content Security Policy (CSP)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In the end, the fix was to add &lt;code&gt;object-src 'self';&lt;/code&gt; to the CSP.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Interesting that other browsers don't require that setting.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/object-src&quot; class=&quot;link link-external&quot;&gt;Read about the &lt;code&gt;object-src&lt;/code&gt; CSP directive on MDN.&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/safari-broken-svg/</id><title>Broken CSS-animated SVG files in Safari and iOS Safari</title><link href="https://mtsknn.fi/blog/safari-broken-svg/" /><published>2021-03-20T12:00:00+03:00</published><updated>2021-03-20T12:00:00+03:00</updated><category term="Safari"></category><category term="SVG"></category><content type="html">&lt;p&gt;Some parts of an SVG were missing and some parts were distorted.
I had to render the SVG via an &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; element
instead of loading it via an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was loading an SVG file via an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.
The SVG file had CSS animations embedded in it.&lt;/p&gt;
&lt;p&gt;Safari and iOS Safari rendered the SVG in a very buggy way:
some parts were missing and some parts were distorted.&lt;/p&gt;
&lt;h2 id=&quot;the-fix&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-fix&quot;&gt;The fix&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I did some quick googling
but didn't find a clear cause.
I did find some speak along the lines of
&amp;quot;Safari is bad at rendering SVGs.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In the end, the fix was to inline the SVG file.&lt;/strong&gt;
I.e. render it directly via an &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; element
instead of loading it via an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;The downside is that now the file can't be cached by the browser.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/firefox-devtools-inactive-css/</id><title>Firefox DevTools can explain why some CSS styles have no effect</title><link href="https://mtsknn.fi/blog/firefox-devtools-inactive-css/" /><published>2021-03-20T12:00:00+03:00</published><updated>2022-12-05T12:00:00+03:00</updated><category term="CSS"></category><category term="CSS for JS Devs course"></category><content type="html">&lt;p&gt;It's frustrating
when a CSS declaration is technically valid
(not crossed out in the browser's DevTools)
but has no effect for some reason.
Firefox DevTools can often tell you why
and also how to potentially fix those issues!
(Update: Chrome 108+ can too.)&lt;/p&gt;
&lt;p&gt;Starting from
&lt;a href=&quot;https://hacks.mozilla.org/2019/10/firefox-70-a-bountiful-release-for-all/&quot; class=&quot;link link-external&quot;&gt;Firefox 70 (released in October 2019)&lt;/a&gt;,
its DevTools contain &amp;quot;inactive CSS rules indicators&amp;quot;
that explain why some styles have no effect:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./firefox-devtools-inactive-css-rule-indicator.png&quot; alt=&quot;Firefox DevTools' inactive CSS rule indicator. Here it's saying that &amp;quot;width has no effect on this element since it has a display of inline. Try adding display:inline-block or display:block.&amp;quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I use Firefox as my daily browser,
but usually switch to Chrome when doing web development
because Firefox DevTools often feel buggy.
Good to know that
Firefox DevTools can be very helpful in these frustrating CSS situations.&lt;/p&gt;
&lt;p&gt;I learned this trick from Josh W Comeau's
&lt;a href=&quot;https://css-for-js.dev/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;CSS for JavaScript Developers&lt;/em&gt; course&lt;/a&gt;
(Module 0).&lt;/p&gt;
&lt;p&gt;Later I also found Elijah Manor's
&lt;a href=&quot;https://elijahmanor.com/blog/firefox-devtools-inactive-css&quot; class=&quot;link link-external&quot;&gt;video explaining the feature&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update on Oct 13, 2022:&lt;/strong&gt;
Jecelyn Yeen just tweeted that
&lt;a href=&quot;https://twitter.com/jecfish/status/1580135502635671552&quot; class=&quot;link link-external&quot;&gt;Chrome Canary has now a similar feature&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update on Dec 5, 2022:&lt;/strong&gt;
The feature is now part of stable Chrome:
&lt;a href=&quot;https://developer.chrome.com/en/blog/new-in-devtools-108/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;What's New In DevTools (Chrome 108)&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/4-types-of-documentation/</id><title>4+ types of documentation</title><link href="https://mtsknn.fi/blog/4-types-of-documentation/" /><published>2021-03-20T12:00:00+03:00</published><updated>2022-04-29T12:00:00+03:00</updated><category term="Documentation"></category><content type="html">&lt;p&gt;Splitting documentation into multiple categories
can make the documentation much clearer.&lt;/p&gt;
&lt;h2 id=&quot;4-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#4-types&quot;&gt;4 types&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://documentation.divio.com/&quot; class=&quot;link link-external&quot;&gt;Divio's documentation system&lt;/a&gt;
splits documentation into four types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tutorials&lt;/strong&gt; are learning-oriented;
they teach how to get started.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How-to guides&lt;/strong&gt; are problem-oriented;
they guide how to achieve a certain goal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explanations&lt;/strong&gt; are understanding-oriented;
they clarify a certain topic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;References&lt;/strong&gt; are information-oriented;
they describe the system and how to use it.
(E.g. what methods are available,
what parameters they take
and what they return.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The four types are quite similar to each other.&lt;/p&gt;
&lt;p&gt;But if you don't realize that there are these different types of documentation,
the types get mixed very easily,
and the documentation gets messy.&lt;/p&gt;
&lt;h3 id=&quot;alternative-descriptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#alternative-descriptions&quot;&gt;Alternative descriptions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;From &lt;a href=&quot;https://old.reddit.com/r/ExperiencedDevs/comments/nmodyl/drunk_post_things_ive_learned_as_a_sr_engineer/h01mflf/&quot; class=&quot;link link-external&quot;&gt;a Reddit comment by Kinrany&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tutorial&lt;/strong&gt;: practical steps for learning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How-to guide&lt;/strong&gt;: practical steps for working.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explanation&lt;/strong&gt;: theoretical knowledge for learning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reference&lt;/strong&gt;: theoretical knowledge for working.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;different-names&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#different-names&quot;&gt;Different names&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A good point from a
&lt;a href=&quot;https://news.ycombinator.com/item?id=26002656&quot; class=&quot;link link-external&quot;&gt;related discussion on Hacker News&lt;/a&gt;:
the different types may have different names.&lt;/p&gt;
&lt;p&gt;For example,
explanations could also be called:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Backgrounds&lt;/li&gt;
&lt;li&gt;Deep dives&lt;/li&gt;
&lt;li&gt;Discussions&lt;/li&gt;
&lt;li&gt;Overviews&lt;/li&gt;
&lt;li&gt;Rationales.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;more-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#more-types&quot;&gt;More types&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another good point from the Hacker News discussion:
there can be other types of documentation as well.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Announcements&lt;/li&gt;
&lt;li&gt;Case studies&lt;/li&gt;
&lt;li&gt;Code samples&lt;/li&gt;
&lt;li&gt;Release notes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These types might fit into one of the four categories,
or they might not.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/ts-param-props/</id><title>Turning constructor params into class props in TypeScript</title><link href="https://mtsknn.fi/blog/ts-param-props/" /><published>2021-03-13T12:00:00+03:00</published><updated>2021-03-13T12:00:00+03:00</updated><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;&amp;quot;Parameter properties&amp;quot; reduce boilerplate in classes,
but they can also make the code hard to read.&lt;/p&gt;
&lt;h2 id=&quot;definition-of-parameter-properties&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#definition-of-parameter-properties&quot;&gt;Definition of parameter properties&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/classes.html#parameter-properties&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Parameter Properties&lt;/em&gt; are defined in the TypeScript docs&lt;/a&gt;
like so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TypeScript offers special syntax
for turning a constructor parameter
into a class property
with the same name and value.
These are called &lt;em&gt;parameter properties&lt;/em&gt;
and are created by prefixing a constructor argument
with one of the visibility modifiers
&lt;code&gt;public&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;protected&lt;/code&gt;, or &lt;code&gt;readonly&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example&quot;&gt;Example&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The two classes below are effectively identical.&lt;/p&gt;
&lt;h3 id=&quot;before-ordinary-class-properties&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#before-ordinary-class-properties&quot;&gt;Before: ordinary class properties&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Ordinary class properties&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; z&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; z&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&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;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; x
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; y
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;z &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z
  &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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;after-parameter-properties&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#after-parameter-properties&quot;&gt;After: parameter properties&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-ts bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Parameter properties&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; z&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
  &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;verdict&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#verdict&quot;&gt;Verdict&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I like that parameter properties reduce boilerplate and verbosity.
But they are potentially confusing
if they are mixed with ordinary class properties –
it might be hard to see at a glance all the properties that the class has.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/js-leap-year/</id><title>Cool way to check for leap years in JavaScript</title><link href="https://mtsknn.fi/blog/js-leap-year/" /><published>2021-03-13T12:00:00+03:00</published><updated>2021-03-13T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Spoiler:
&lt;code&gt;new Date(year, 1, 29).getDate() === 29&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I stumbled upon
&lt;a href=&quot;https://twitter.com/colindecarlo/status/1360617963297112066&quot; class=&quot;link link-external&quot;&gt;a tweet by Colin DeCarlo&lt;/a&gt;
about a cool way to check if a given year is a leap year
(code by JleCoRyl3):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isLearYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;year&lt;/span&gt;&lt;span class=&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 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;year&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 number&quot;&gt;29&lt;/span&gt;&lt;span class=&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;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 operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;29&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quite clever!
Though a bit confusing at first
because months are 0-indexed.
Maybe a code comment would be in order.&lt;/p&gt;
&lt;p&gt;The tweet is what inspired me to start doing
TypeScript exercises on &lt;a href=&quot;https://exercism.org/&quot; class=&quot;link link-external&quot;&gt;Exercism&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/csharp-nsubstitute/</id><title>Cleaner unit test mocking in C# with NSubstitute</title><link href="https://mtsknn.fi/blog/csharp-nsubstitute/" /><published>2021-03-13T12:00:00+03:00</published><updated>2021-03-13T12:00:00+03:00</updated><category term="C#"></category><category term="Testing"></category><content type="html">&lt;p&gt;The NSubstitute package simplifies
how mock implementations are created
and how mocks are used.&lt;/p&gt;
&lt;h2 id=&quot;moq&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#moq&quot;&gt;Moq&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have previously used
&lt;a href=&quot;https://github.com/moq/moq4&quot; class=&quot;link link-external&quot;&gt;Moq, &amp;quot;the most popular and friendly mocking library for .NET,&amp;quot;&lt;/a&gt;
to do mocking in unit tests.&lt;/p&gt;
&lt;p&gt;Example from &lt;a href=&quot;https://www.youtube.com/watch?v=9ZvDBSQa_so&quot; class=&quot;link link-external&quot;&gt;Nick Chapsas's video on the Moq package&lt;/a&gt;
(&lt;code&gt;_sut&lt;/code&gt; = system under test):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomerService&lt;/span&gt; _sut&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ICustomerRepository&lt;/span&gt; _customerRepositoryMock &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 constructor-invocation class-name&quot;&gt;Mock&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ICustomerRepository&lt;span class=&quot;token punctuation&quot;&gt;&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 keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ILoggingService&lt;/span&gt; _loggerMock &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 constructor-invocation class-name&quot;&gt;Mock&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ILoggingService&lt;span class=&quot;token punctuation&quot;&gt;&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 keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CustomerServiceTests&lt;/span&gt;&lt;span class=&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;
    _sut &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 constructor-invocation class-name&quot;&gt;CustomerService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_customerRepositoryMock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _loggerMock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Object&lt;span class=&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 attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Fact&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetByIdAsync_ShouldReturnCustomer_WhenCustomerExists&lt;/span&gt;&lt;span class=&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;// ...&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Mock implementation&lt;/span&gt;
    _customerRepositoryMock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetByIdAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerId&lt;span class=&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;ReturnsAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerDto&lt;span class=&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;// ...&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;nsubstitute&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#nsubstitute&quot;&gt;NSubstitute&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LcQYv0cBWk0&quot; class=&quot;link link-external&quot;&gt;Nick Chapsas's video on the NSubstitute package&lt;/a&gt;
convinced me that
&lt;a href=&quot;https://nsubstitute.github.io/&quot; class=&quot;link link-external&quot;&gt;NSubstitute, &amp;quot;a friendly substitute for .NET mocking libraries,&amp;quot;&lt;/a&gt;
could be nicer.&lt;/p&gt;
&lt;p&gt;Example from the video:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomerService&lt;/span&gt; _sut&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ICustomerRepository&lt;/span&gt; _customerRepository &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Substitute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;For&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ICustomerRepository&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ILoggingService&lt;/span&gt; _logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Substitute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;For&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ILoggingService&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CustomerServiceTests&lt;/span&gt;&lt;span class=&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;
    _sut &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 constructor-invocation class-name&quot;&gt;CustomerService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_customerRepository&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _logger&lt;span class=&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 attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Fact&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetByIdAsync_ShouldReturnCustomer_WhenCustomerExists&lt;/span&gt;&lt;span class=&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;// ...&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Mock implementation&lt;/span&gt;
    _customerRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetByIdAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerId&lt;span class=&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;Returns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerDto&lt;span class=&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;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;differences-to-moq&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#differences-to-moq&quot;&gt;Differences to Moq&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No need to use &lt;code&gt;.Object&lt;/code&gt; in various places.&lt;/li&gt;
&lt;li&gt;Creating mock implementations is more straightforward.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/csharp-fluent-assertions/</id><title>Cleaner unit test assertions in C# with Fluent Assertions</title><link href="https://mtsknn.fi/blog/csharp-fluent-assertions/" /><published>2021-03-13T12:00:00+03:00</published><updated>2021-03-13T12:00:00+03:00</updated><category term="C#"></category><category term="Testing"></category><content type="html">&lt;p&gt;The Fluent Assertions package makes unit test assertions read like English
and also improves the error messages.&lt;/p&gt;
&lt;p&gt;Watching &lt;a href=&quot;https://www.youtube.com/watch?v=b2zxl5zNjlA&quot; class=&quot;link link-external&quot;&gt;Nick Chapsas's video on the Fluent Assertions package&lt;/a&gt;
made me want to start using &lt;a href=&quot;https://fluentassertions.com/&quot; class=&quot;link link-external&quot;&gt;Fluent Assertions&lt;/a&gt; at work.&lt;/p&gt;
&lt;p&gt;Example from the video (&lt;code&gt;_sut&lt;/code&gt; = system under test):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before&lt;/span&gt;
Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;StartsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;The result is: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _sut&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;EndsWith&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;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&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; _sut&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Text&lt;span class=&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;// After&lt;/span&gt;
result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Should&lt;/span&gt;&lt;span class=&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;Be&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
_sut&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Should&lt;/span&gt;&lt;span class=&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;StartWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;The result is: &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;
_sut&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Should&lt;/span&gt;&lt;span class=&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;EndWith&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;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So much better.
Reads like English.&lt;/p&gt;
&lt;p&gt;Another benefit is that the messages from failed assertions are more detailed.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-disable-imageprocessors-upscaling-feature/</id><title>How to disable ImageProcessor's upscaling feature</title><link href="https://mtsknn.fi/blog/how-to-disable-imageprocessors-upscaling-feature/" /><published>2021-03-10T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="C#"></category><category term="Episerver"></category><content type="html">&lt;p&gt;Disabling the upscaling feature (by default or completely)
can be done via ImageProcessor's &lt;code&gt;ValidatingRequest&lt;/code&gt; event.
It's not possible via a config file.&lt;/p&gt;
&lt;h2 id=&quot;whats-upscaling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-upscaling&quot;&gt;What's upscaling?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://imageprocessor.org/imageprocessor-web/imageprocessingmodule/resize/&quot; class=&quot;link link-external&quot;&gt;ImageProcessor's resize method&lt;/a&gt;
lets you modify the dimensions of an image on the fly,
by using URL parameters.
For example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;/my-image.jpg?width=2000&amp;amp;height=1000&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;/my-image.jpg?width=2000&amp;amp;heightratio=0.5625&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upscaling means that
&lt;strong&gt;an image is resized to dimensions greater than its original dimensions&lt;/strong&gt;.
This can cause blurry images,
so you might want to disable the upscaling feature.&lt;/p&gt;
&lt;p&gt;You can disable upscaling on a case-by-case basis
with the &lt;code&gt;upscale&lt;/code&gt; URL parameter:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;/my-image.jpg?width=2000&amp;amp;height=1000&amp;amp;upscale=false&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 comment&quot;&gt;&amp;lt;!--                                                 ^^^^^^^^^^^^^^ --&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doing so manually will however quickly become cumbersome.
Let's see how to disable it programmatically.&lt;/p&gt;
&lt;h2 id=&quot;not-possible-via-a-config-file&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#not-possible-via-a-config-file&quot;&gt;Not possible via a config file&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;According to
&lt;a href=&quot;https://github.com/JimBobSquarePants/ImageProcessor/issues/583&quot; class=&quot;link link-external&quot;&gt;GitHub issue #583&lt;/a&gt;
and
&lt;a href=&quot;https://github.com/JimBobSquarePants/ImageProcessor/issues/767&quot; class=&quot;link link-external&quot;&gt;issue #767&lt;/a&gt;,
it's not possible to disable the upscaling feature via a config file.&lt;/p&gt;
&lt;h2 id=&quot;disable-via-an-event&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#disable-via-an-event&quot;&gt;Disable via an event&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The disabling of the upscaling feature
needs to be done via ImageProcessor's &lt;code&gt;ValidatingRequest&lt;/code&gt; event.
See the
&lt;a href=&quot;https://imageprocessor.org/imageprocessor-web/imageprocessingmodule/#events&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Events&lt;/em&gt; section in ImageProcessor's docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Add the code maybe to the &lt;code&gt;Application_Start&lt;/code&gt; event in &lt;code&gt;Global.asax&lt;/code&gt;.
Or if using Episerver,
&lt;a href=&quot;https://world.episerver.com/documentation/developer-guides/CMS/initialization/Creating-an-initialization-module/&quot; class=&quot;link link-external&quot;&gt;create an initialization module&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;InitializableModule&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageProcessorEventsInitialization&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;IInitializableModule&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;InitializationEngine&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ImageProcessingModule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ValidatingRequest &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; DisableUpscalingByDefault&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
        ImageProcessingModule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ValidatingRequest &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; DisableUpscaling&lt;span class=&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;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Uninitialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;InitializationEngine&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ImageProcessingModule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ValidatingRequest &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; DisableUpscalingByDefault&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
        ImageProcessingModule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ValidatingRequest &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; DisableUpscaling&lt;span class=&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;private&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DisableUpscalingByDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ImageProcessingModule&lt;/span&gt; sender&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValidatingRequestEventArgs&lt;/span&gt; args&lt;span class=&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;// ...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DisableUpscaling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ImageProcessingModule&lt;/span&gt; sender&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValidatingRequestEventArgs&lt;/span&gt; args&lt;span class=&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;// ...&lt;/span&gt;
    &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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;disable-by-default&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#disable-by-default&quot;&gt;Disable by default&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;summary&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Disable ImageProcessor's upscaling feature by default.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Upscaling can be enabled for individual images&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     with the &amp;lt;c&gt;upscale=true&amp;lt;/c&gt; URL parameter.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;/summary&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;remarks&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Not possible via configuration:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     &amp;lt;list type=&quot;bullet&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///         &amp;lt;item&gt;https://imageprocessor.org/imageprocessor-web/imageprocessingmodule/#events&amp;lt;/item&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///         &amp;lt;item&gt;https://github.com/JimBobSquarePants/ImageProcessor/issues/583&amp;lt;/item&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///         &amp;lt;item&gt;https://github.com/JimBobSquarePants/ImageProcessor/issues/767&amp;lt;/item&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     &amp;lt;/list&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Code from https://mtsknn.fi/blog/how-to-disable-imageprocessors-upscaling-feature/&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;/remarks&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DisableUpscalingByDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ImageProcessingModule&lt;/span&gt; sender&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValidatingRequestEventArgs&lt;/span&gt; args&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QueryString&lt;span class=&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;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; queryCollection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; HttpUtility&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ParseQueryString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QueryString&lt;span class=&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;// The URL parameter has already been set,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// so let's not modify it&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queryCollection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AllKeys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;upscale&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;
        &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 punctuation&quot;&gt;}&lt;/span&gt;

    queryCollection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;upscale&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;false&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;
    args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QueryString &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; queryCollection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;disable-completely&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#disable-completely&quot;&gt;Disable completely&lt;/a&gt;&lt;/h3&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;summary&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Disable ImageProcessor's upscaling feature completely.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Image URLs' &amp;lt;c&gt;upscale&amp;lt;/c&gt; URL parameter won't have any effect.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;/summary&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;remarks&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Not possible via configuration:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     &amp;lt;list type=&quot;bullet&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///         &amp;lt;item&gt;https://imageprocessor.org/imageprocessor-web/imageprocessingmodule/#events&amp;lt;/item&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///         &amp;lt;item&gt;https://github.com/JimBobSquarePants/ImageProcessor/issues/583&amp;lt;/item&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///         &amp;lt;item&gt;https://github.com/JimBobSquarePants/ImageProcessor/issues/767&amp;lt;/item&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     &amp;lt;/list&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;///     Code from https://mtsknn.fi/blog/how-to-disable-imageprocessors-upscaling-feature/&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/// &amp;lt;/remarks&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DisableUpscaling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ImageProcessingModule&lt;/span&gt; sender&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValidatingRequestEventArgs&lt;/span&gt; args&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QueryString&lt;span class=&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;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; queryCollection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; HttpUtility&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ParseQueryString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QueryString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    queryCollection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;upscale&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;false&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;
    args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QueryString &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; queryCollection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the usage of
&lt;code&gt;queryCollection.Set()&lt;/code&gt;
instead of
&lt;code&gt;queryCollection.Add()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#source&quot;&gt;Source&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Original solution found in the
&lt;a href=&quot;https://github.com/JimBobSquarePants/ImageProcessor/issues/583&quot; class=&quot;link link-external&quot;&gt;GitHub issue #583&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/dotnet-refactoring/</id><title>My notes on two nice .NET refactoring videos</title><link href="https://mtsknn.fi/blog/dotnet-refactoring/" /><published>2021-03-06T12:00:00+03:00</published><updated>2021-03-06T12:00:00+03:00</updated><category term="C#"></category><category term="Testing"></category><content type="html">&lt;p&gt;YouTube recommended me a two-part video series
that was fun to watch and gave me a few lightbulb thoughts.&lt;/p&gt;
&lt;h2 id=&quot;part-1-preparations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#part-1-preparations&quot;&gt;Part 1: preparations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;YouTube recommended me
&lt;a href=&quot;https://www.youtube.com/watch?v=U3QvTaw224o&quot; class=&quot;link link-external&quot;&gt;Nick Chapsas's video (part 1) about refactoring some .NET code&lt;/a&gt;.
It was great.&lt;/p&gt;
&lt;p&gt;In the first part of the two-part video series,
Nick makes the code testable by extracting its dependencies
and injecting them back via constructor injection.
This way the dependencies can be mocked in unit tests.&lt;/p&gt;
&lt;p&gt;Then he creates unit tests for the code before doing any refactoring.
Otherwise it would be too easy to accidentally modify the logic of the code.&lt;/p&gt;
&lt;h2 id=&quot;part-2-refactorings&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#part-2-refactorings&quot;&gt;Part 2: refactorings&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&quot;https://www.youtube.com/watch?v=Yd4GnWeEkIY&quot; class=&quot;link link-external&quot;&gt;part 2 video&lt;/a&gt;,
Nick does the actual refactoring.
Three things struck in my mind.&lt;/p&gt;
&lt;h3 id=&quot;renaming-method-parameters-can-cause-backwards-incompatibility-in-csharp&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#renaming-method-parameters-can-cause-backwards-incompatibility-in-csharp&quot;&gt;Renaming method parameters can cause backwards incompatibility in C#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One method parameter has a typo in its name.
It would be tempting to rename it,
but it would be a breaking change to the consumers of the code
(warranting a major version increment)
because C# supports
&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments&quot; class=&quot;link link-external&quot;&gt;named arguments&lt;/a&gt;.
That's a good point that I would have missed.&lt;/p&gt;
&lt;h3 id=&quot;when-are-interfaces-needed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#when-are-interfaces-needed&quot;&gt;When are interfaces needed?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Nick creates interfaces for the extracted dependencies
to make them mockable,
expect for one class.
That class doesn't need mocking,
so it doesn't necessarily need an interface.&lt;/p&gt;
&lt;h3 id=&quot;using-tuples-instead-of-creating-simple-classes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#using-tuples-instead-of-creating-simple-classes&quot;&gt;Using tuples instead of creating simple classes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One method needs to return two values.
You could create a simple class for the return value,
but Nick uses a
&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples&quot; class=&quot;link link-external&quot;&gt;tuple&lt;/a&gt;,
skipping the need for creating that simple class.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/css-will-change/</id><title>Smoother CSS animations with the `will-change` property</title><link href="https://mtsknn.fi/blog/css-will-change/" /><published>2021-03-06T12:00:00+03:00</published><updated>2021-03-06T12:00:00+03:00</updated><category term="CSS"></category><content type="html">&lt;p&gt;The &lt;code&gt;will-change&lt;/code&gt; property makes the browser render an element with the GPU,
which can reduce jankiness and also allows utilizing sub-pixel rendering.
But use the property sparingly.&lt;/p&gt;
&lt;h2 id=&quot;cpu-vs-gpu&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cpu-vs-gpu&quot;&gt;CPU vs GPU&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The beginning and ending of CSS animations can sometimes be glitchy
because some property transitions (like &lt;code&gt;transform&lt;/code&gt;) are rendered with the GPU,
whereas the elements are otherwise rendered with the CPU.&lt;/p&gt;
&lt;p&gt;I learned about the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/will-change&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;will-change&lt;/code&gt; CSS property&lt;/a&gt;
from Josh W Comeau's comprehensive article
&lt;a href=&quot;https://www.joshwcomeau.com/animation/css-transitions/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;An Interactive Guide to CSS Transitions&lt;/em&gt;&lt;/a&gt;.
From the &lt;a href=&quot;https://www.joshwcomeau.com/animation/css-transitions/#hardware-acceleration&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Hardware acceleration&lt;/em&gt; section&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GPUs and CPUs render things &lt;em&gt;slightly&lt;/em&gt; differently. [...]&lt;/p&gt;
&lt;p&gt;We can fix this problem by adding the following CSS property:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.btn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;will-change&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transform&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;will-change&lt;/code&gt; is a property that allows us to hint to the browser that
we're going to animate the selected element,
and that it should optimize for this case.&lt;/p&gt;
&lt;p&gt;In practice,
what this means is that
the browser will let the GPU handle this element &lt;em&gt;all the time&lt;/em&gt;.
No more handing-off between CPU and GPU,
no more telltale &amp;quot;snapping into place&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;sub-pixel-rendering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sub-pixel-rendering&quot;&gt;Sub-pixel rendering&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;There's another benefit to hardware acceleration:
we can take advantage of &lt;em&gt;sub-pixel rendering&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Properties like &lt;code&gt;margin-top&lt;/code&gt; can't sub-pixel-render,
which means they need to round to the nearest pixel,
creating a stepped, janky effect.
&lt;code&gt;transform&lt;/code&gt;, meanwhile,
can smoothly shift between pixels,
thanks to the GPU's anti-aliasing trickery.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;use-will-change-sparingly&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#use-will-change-sparingly&quot;&gt;Use &lt;code&gt;will-change&lt;/code&gt; sparingly&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Note however that you shouldn't overuse the &lt;code&gt;will-change&lt;/code&gt; property,
like Josh later mentions.
It's also mentioned on the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/will-change&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;&lt;code&gt;will-change&lt;/code&gt;&lt;/em&gt; page on MDN&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; &lt;code&gt;will-change&lt;/code&gt; is intended to be used as a last resort,
in order to try to deal with existing performance problems.
It should not be used to anticipate performance problems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If everything (every animation or transition) is prioritized, nothing is.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/css-flow-root/</id><title>CSS: `display: flow-root` is better than the clearfix hack</title><link href="https://mtsknn.fi/blog/css-flow-root/" /><published>2021-03-06T12:00:00+03:00</published><updated>2021-03-06T12:00:00+03:00</updated><category term="CSS"></category><content type="html">&lt;p&gt;The &lt;code&gt;flow-root&lt;/code&gt; value is clearer (no hacks!)
and has great browser support.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://caniuse.com/flow-root&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;display: flow-root&lt;/code&gt; is described on &lt;em&gt;Can I use&lt;/em&gt;&lt;/a&gt;
like so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The element generates a block container box,
and lays out its contents using flow layout.
It always establishes a new block formatting context for its contents.
It provides a better solution to the most use cases of the &amp;quot;clearfix&amp;quot; hack.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The browser support of the &lt;code&gt;flow-root&lt;/code&gt; value is excellent
(supported by all modern browsers).
That's quite funny,
because I don't remember hearing about this value before.
I also don't remember where I found it.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/action-driven-css-animations/</id><title>Action-driven CSS animations</title><link href="https://mtsknn.fi/blog/action-driven-css-animations/" /><published>2021-03-06T12:00:00+03:00</published><updated>2021-03-06T12:00:00+03:00</updated><category term="CSS"></category><content type="html">&lt;p&gt;Polish your animations by animating based on actions or events,
like mouse-enter and mouse-leave,
instead of animating based on states,
like default and hover state.&lt;/p&gt;
&lt;p&gt;I got the idea from
Josh W Comeau's comprehensive article
&lt;a href=&quot;https://www.joshwcomeau.com/animation/css-transitions/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;An Interactive Guide to CSS Transitions&lt;/em&gt;&lt;/a&gt;.
From the &lt;a href=&quot;https://www.joshwcomeau.com/animation/css-transitions/#action-driven-motion&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Action-driven motion&lt;/em&gt; section&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I believe most developers think in terms of &lt;em&gt;states&lt;/em&gt;:
for example,
you might look at this situation
and say that we have a &amp;quot;hover&amp;quot; state and a default state.
Instead,
what if we thought in terms of &lt;em&gt;actions&lt;/em&gt;?
We animate based on what the user is doing,
thinking in terms of events,
not states.
We have a mouse-enter animation and a mouse-leave animation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;example-modals&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-modals&quot;&gt;Example: modals&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Another common example is modals.
It can be useful for modals to enter with an &lt;code&gt;ease-out&lt;/code&gt; animation,
and to exit with a quicker &lt;code&gt;ease-in&lt;/code&gt; animation.&lt;/p&gt;
&lt;p&gt;This is a small detail,
but it speaks to a much larger idea.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Exiting a modal quickly is great
because if the user has closed the modal,
they are not interested in it anymore.
Having to watch the modal slide away slowly would be pointless.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/casting-in-csharp-cast-expression-vs-as-and-is-operators/</id><title>Casting in C#: cast expression vs `as` and `is` operators</title><link href="https://mtsknn.fi/blog/casting-in-csharp-cast-expression-vs-as-and-is-operators/" /><published>2021-03-03T12:00:00+03:00</published><updated>2021-06-11T12:00:00+03:00</updated><category term="C#"></category><category term="Mnemonics"></category><content type="html">&lt;p&gt;A cast expression like &lt;code&gt;(string)foo&lt;/code&gt; throws
if the types don't match.
The &lt;code&gt;as&lt;/code&gt; operator doesn't throw
and defaults to &lt;code&gt;null&lt;/code&gt;.
The &lt;code&gt;is&lt;/code&gt; operator doesn't throw
and ignores &lt;code&gt;null&lt;/code&gt;s.&lt;/p&gt;
&lt;h2 id=&quot;cast-expression&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cast-expression&quot;&gt;Cast expression&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes called &amp;quot;direct casting.&amp;quot;&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; bar &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 keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// `bar` is a `string` (can be `null`)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;InvalidCastException&lt;/span&gt;&lt;span class=&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;// `foo` is not a `string`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;foo&lt;/code&gt; is not a &lt;code&gt;string&lt;/code&gt;: throws &lt;code&gt;InvalidCastException&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Otherwise assigns &lt;code&gt;foo&lt;/code&gt; to &lt;code&gt;bar&lt;/code&gt; (can be &lt;code&gt;null&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Use when you are sure that the type is correct.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;as-operator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#as-operator&quot;&gt;&lt;code&gt;as&lt;/code&gt; operator&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; bar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; foo &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bar &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// `bar` is a `string` and not `null`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;foo&lt;/code&gt; is not a &lt;code&gt;string&lt;/code&gt;: assigns &lt;code&gt;null&lt;/code&gt; to &lt;code&gt;bar&lt;/code&gt;; doesn't throw.&lt;/li&gt;
&lt;li&gt;Otherwise assigns &lt;code&gt;foo&lt;/code&gt; to &lt;code&gt;bar&lt;/code&gt; (can be &lt;code&gt;null&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Use when the type &lt;em&gt;might&lt;/em&gt; be correct.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;is-operator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#is-operator&quot;&gt;&lt;code&gt;is&lt;/code&gt; operator&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&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 comment&quot;&gt;// `foo` is a `string` and not `null`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; bar&lt;span class=&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;// `bar` is a `string` and not `null`&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;foo&lt;/code&gt; is not a &lt;code&gt;string&lt;/code&gt; or is &lt;code&gt;null&lt;/code&gt;: returns &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Otherwise returns &lt;code&gt;true&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;Also in the second example above:
assigns &lt;code&gt;foo&lt;/code&gt; to a new variable &lt;code&gt;bar&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use in &lt;code&gt;if&lt;/code&gt; statements
to combine the usage of the &lt;code&gt;as&lt;/code&gt; operator and &lt;code&gt;null&lt;/code&gt; check.&lt;/li&gt;
&lt;li&gt;Use in &lt;code&gt;switch&lt;/code&gt; statements for
&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#type-pattern&quot; class=&quot;link link-external&quot;&gt;type pattern matching&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;mnemonic-cast-expression-vs-as-operator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#mnemonic-cast-expression-vs-as-operator&quot;&gt;Mnemonic: cast expression vs &lt;code&gt;as&lt;/code&gt; operator&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use the &lt;code&gt;as&lt;/code&gt; operator
when you only &lt;strong&gt;as&lt;/strong&gt;-sume&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; that the type is correct.
If your assumption is incorrect,
that's okay!
You'll get a &lt;code&gt;null&lt;/code&gt;
and no exception will be thrown.&lt;/p&gt;
&lt;p&gt;Conversely,
if you are sure that the type is correct,
use a cast &lt;strong&gt;ex&lt;/strong&gt;-pression.
You'll be punished with an &lt;strong&gt;ex&lt;/strong&gt;-ception
if you are wrong.&lt;/p&gt;
&lt;h2 id=&quot;sources-further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sources-further-resources&quot;&gt;Sources / Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/132445/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Direct casting vs 'as' operator?&lt;/em&gt; on Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Cast expression&lt;/em&gt; on Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;&lt;code&gt;as&lt;/code&gt; operator&lt;/em&gt; on Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;&lt;code&gt;is&lt;/code&gt; operator&lt;/em&gt; on Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#type-testing-with-pattern-matching&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Type testing with pattern matching&lt;/em&gt; on Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;See
&lt;a href=&quot;https://mtsknn.fi/blog/assume-vs-presume-in-english/&quot; class=&quot;link&quot;&gt;&lt;em&gt;English: assume vs presume&lt;/em&gt;&lt;/a&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/tests-from-user-perspective/</id><title>Name front-end test cases from user perspective</title><link href="https://mtsknn.fi/blog/tests-from-user-perspective/" /><published>2021-02-27T12:00:00+03:00</published><updated>2021-02-27T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><category term="Testing"></category><content type="html">&lt;p&gt;Such naming helps you create tests that resemble the way your users use your app.&lt;/p&gt;
&lt;p&gt;I noticed that
a colleague from another team
had named their test cases from user perspective,
like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'&amp;lt;FooComponent&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 operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'user can see all options'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&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;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'user can toggle between options'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&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;// etc.&lt;/span&gt;
&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;I was already familiar with
the primary guiding principle of
&lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro&quot; class=&quot;link link-external&quot;&gt;React Testing Library&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The more your tests resemble the way your software is used,
the more confidence they can give you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But I hadn't thought of naming test cases from this perspective.
Makes sense, though!
&lt;strong&gt;Naming test cases from user perspective helps you create good tests&lt;/strong&gt; –
tests that resemble the way your users use your app.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/episerver-automapper/</id><title>Episerver + AutoMapper is a confusing combo</title><link href="https://mtsknn.fi/blog/episerver-automapper/" /><published>2021-02-27T12:00:00+03:00</published><updated>2021-02-27T12:00:00+03:00</updated><category term="C#"></category><category term="Episerver"></category><content type="html">&lt;p&gt;Blocks in Episerver implement the &lt;code&gt;IContent&lt;/code&gt; interface only during runtime
which makes using AutoMapper difficult.&lt;/p&gt;
&lt;p&gt;A few weeks ago I started using &lt;a href=&quot;https://automapper.org/&quot; class=&quot;link link-external&quot;&gt;AutoMapper&lt;/a&gt;
in an &lt;a href=&quot;https://www.episerver.com/&quot; class=&quot;link link-external&quot;&gt;Episerver (.NET CMS)&lt;/a&gt; project
to map models to view models semi-automatically.&lt;/p&gt;
&lt;p&gt;My initial feelings: 😻&lt;/p&gt;
&lt;p&gt;It was quite nice until I started creating mappings for &lt;em&gt;blocks&lt;/em&gt; (reusable pieces of content).&lt;/p&gt;
&lt;p&gt;My feelings now: 😿😾&lt;/p&gt;
&lt;p&gt;Whereas page models implement Episerver's &lt;code&gt;IContent&lt;/code&gt; interface &amp;quot;normally,&amp;quot;
&lt;a href=&quot;https://world.episerver.com/blogs/Johan-Bjornfot/Dates1/2012/11/Shared-blocks--IContent/&quot; class=&quot;link link-external&quot;&gt;block models implement the &lt;code&gt;IContent&lt;/code&gt; interface &lt;em&gt;only during runtime&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This means that
creating a mapping from &lt;code&gt;IContent&lt;/code&gt; to a block type is not possible.
At least not possible in this way that I tried:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Base view model for pages and blocks&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IContentViewModel&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; ContentLink &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; ContentType &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt;&lt;span class=&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;// etc.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IContentProfile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IContentProfile&lt;/span&gt;&lt;span class=&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 generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;CreateMap&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;IContent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; IContentViewModel&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyPageViewModel&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;IContentViewModel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyPageProfile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyPageProfile&lt;/span&gt;&lt;span class=&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 generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;CreateMap&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;MyPage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MyPageViewModel&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 comment&quot;&gt;// `MyPage` implements `IContent`, so this is ok:&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;IncludeBase&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;IContent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; IContentViewModel&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyBlockViewModel&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;IContentViewModel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyBlockProfile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyBlockProfile&lt;/span&gt;&lt;span class=&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 generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;CreateMap&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;MyBlock&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MyBlockViewModel&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 comment&quot;&gt;// Error! `MyBlock` doesn't implement `IContent` until runtime,&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// so this doesn't work:&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;IncludeBase&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;IContent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; IContentViewModel&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I eventually came up with a solution,
but it feels &lt;em&gt;very&lt;/em&gt; complex and &lt;em&gt;very&lt;/em&gt; verbose.&lt;/p&gt;
&lt;p&gt;I don't know if AutoMapper should be this difficult.
If you are working on an Episerver project,
my suggestion would be to research alternative mappers or do mappings manually.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/accessible-test-queries/</id><title>Prefer accessible queries with (React) Testing Library</title><link href="https://mtsknn.fi/blog/accessible-test-queries/" /><published>2021-02-27T12:00:00+03:00</published><updated>2021-02-27T12:00:00+03:00</updated><category term="Accessibility"></category><category term="JavaScript"></category><category term="React"></category><category term="Testing"></category><content type="html">&lt;p&gt;Accessible queries take into account the semantic meaning of HTML elements.
Such queries help you write more accessible apps.&lt;/p&gt;
&lt;p&gt;Your app probably has lots of text in various kinds of HTML elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;headings (&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; – &lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;paragraphs (&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;form labels (&lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What is the semantic meaning of each element?&lt;/p&gt;
&lt;p&gt;Does your app have,
or should it have,
meaningful text in elements without a semantic meaning?
Apart from plain paragraphs,
probably not!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://testing-library.com/&quot; class=&quot;link link-external&quot;&gt;Testing Library's&lt;/a&gt; methods &lt;code&gt;getByText()&lt;/code&gt;, &lt;code&gt;queryByText()&lt;/code&gt; and &lt;code&gt;findByText()&lt;/code&gt;
search for all elements;
they don't care about the elements' semantic meanings.
Because most text should be in elements with specific semantic meanings,
&lt;strong&gt;these methods should be used sparingly&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For example,
don't look for a button using the &lt;code&gt;getByText()&lt;/code&gt; method
because the test could pass
even if the button was implemented in a hacky way&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.
Use the &lt;code&gt;getByRole()&lt;/code&gt; method instead:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getByRole&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'button'&lt;/span&gt;&lt;span class=&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;name&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;submit&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures that the button you are looking for
is implemented properly and in an accessible way.&lt;/p&gt;
&lt;p&gt;So:
&lt;strong&gt;prefer more specific queries than the basic &lt;code&gt;*ByText()&lt;/code&gt; methods&lt;/strong&gt;.
See
&lt;a href=&quot;https://testing-library.com/docs/queries/about#priority&quot; class=&quot;link link-external&quot;&gt;list of recommended prioritizations of the different queries&lt;/a&gt;.&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;Think of a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with a click handler.
Don't do it, kids – use a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/assume-vs-presume-in-english/</id><title>Assume vs presume in English</title><link href="https://mtsknn.fi/blog/assume-vs-presume-in-english/" /><published>2021-02-25T12:00:00+03:00</published><updated>2021-06-11T12:00:00+03:00</updated><category term="English"></category><category term="Mnemonics"></category><content type="html">&lt;p&gt;Both are guesses.
Assume is weaker (little or no evidence),
presume is stronger (reasonable evidence).
But how to remember which is which?&lt;/p&gt;
&lt;h2 id=&quot;definitions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#definitions&quot;&gt;Definitions&lt;/a&gt;&lt;/h2&gt;
&lt;dl&gt;
&lt;dt&gt;Assume&lt;/dt&gt;
&lt;dd&gt;Make a guess based on little or no evidence.&lt;/dd&gt;
&lt;dt&gt;Presume&lt;/dt&gt;
&lt;dd&gt;Make an informed guess based on reasonable evidence.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Source for the word definitions:
&lt;a href=&quot;https://www.merriam-webster.com/words-at-play/assume-vs-presume&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Are 'Assume' and 'Presume' Synonyms?&lt;/em&gt; on Merriam-Webster&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mnemonics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#mnemonics&quot;&gt;Mnemonics&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;When you &lt;strong&gt;ass&lt;/strong&gt;-ume something,
it's just a guess that you have pulled from your &lt;strong&gt;ass&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;When you &lt;strong&gt;pre&lt;/strong&gt;-sume something,
you have some &lt;strong&gt;pre&lt;/strong&gt;-knowledge or &lt;strong&gt;pre&lt;/strong&gt;-information
to support your guess.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Source for the mnemonics:
I pulled them from my ass!&lt;/p&gt;
&lt;h2 id=&quot;suppose&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#suppose&quot;&gt;Suppose?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I &lt;em&gt;suppose&lt;/em&gt; I should add a third word to the comparison: suppose.
Coming soon™.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-quickly-count-source-lines-of-code-using-npx-cloc/</id><title>How to quickly count (source) lines of code using `npx cloc`</title><link href="https://mtsknn.fi/blog/how-to-quickly-count-source-lines-of-code-using-npx-cloc/" /><published>2021-02-24T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="Cool tools"></category><content type="html">&lt;p&gt;Run &lt;code&gt;npx cloc [options] &amp;lt;files/dirs&amp;gt;&lt;/code&gt;.
E.g. &lt;code&gt;npx cloc src/&lt;/code&gt; or &lt;code&gt;npx cloc foo.js bar.css&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The
&lt;a href=&quot;https://github.com/kentcdodds/cloc&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;cloc&lt;/code&gt; npm package&lt;/a&gt;
by Kent C. Dodds
is a wrapper around the
&lt;a href=&quot;https://github.com/AlDanial/cloc&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;cloc&lt;/code&gt; command line program&lt;/a&gt;
by Al Danial.&lt;/p&gt;
&lt;p&gt;Example from this repo:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-text bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;$ npx cloc . \
    --exclude-dir=_sample-content,_site,node_modules \
    --not-match-f=package-lock.json

npx: installed 1 in 1.085s
     172 text files.
     162 unique files.
      49 files ignored.

github.com/AlDanial/cloc v 1.90  T=0.22 s (707.6 files/s, 59215.9 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Markdown                       100           1947              0           8129
JavaScript                      27            114            110            848
Pug                             18             78            123            789
CSS                              1             34             31            328
TOML                             1             31              2            127
JSON                             2              0              0             67
YAML                             1              2              2             12
XML                              1              0              0              8
Bourne Shell                     1              4              9              7
SVG                              1              0              0              1
-------------------------------------------------------------------------------
SUM:                           153           2210            277          10316
-------------------------------------------------------------------------------
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;npx cloc&lt;/code&gt; or &lt;code&gt;npx cloc --help&lt;/code&gt; for more options and information.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-exclude-your-own-mobile-browser-visits-from-plausible-analytics/</id><title>Excluding your own mobile browser visits from Plausible Analytics</title><link href="https://mtsknn.fi/blog/how-to-exclude-your-own-mobile-browser-visits-from-plausible-analytics/" /><published>2021-02-17T12:00:00+03:00</published><updated>2021-06-19T12:00:00+03:00</updated><category term="Bookmarklets"></category><content type="html">&lt;p&gt;Use a bookmarklet
to stop Plausible Analytics
from counting your own visits
made using mobile devices.&lt;/p&gt;
&lt;h2 id=&quot;excluding-desktop-browsers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#excluding-desktop-browsers&quot;&gt;Excluding desktop browsers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;
Run &lt;code&gt;localStorage.plausible_ignore = true&lt;/code&gt; in the browser's console
to start excluding your own visits.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://plausible.io/docs/excluding-localstorage&quot; class=&quot;link link-external&quot;&gt;More specific instructions in Plausible docs.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;excluding-mobile-browsers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#excluding-mobile-browsers&quot;&gt;Excluding mobile browsers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We need to set the &lt;code&gt;localStorage&lt;/code&gt; item mentioned in the previous section.&lt;/p&gt;
&lt;p&gt;However,
running code in a browser's console on an Android device is a hassle&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.
Running code in iOS Safari's console is also a hassle&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;,
and only possible if you have a Mac as far as I know.&lt;/p&gt;
&lt;h3 id=&quot;what-doesnt-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#what-doesnt-work&quot;&gt;What doesn't work&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You could try pasting the following code to the browser's URL bar
and then executing it by &amp;quot;visiting&amp;quot; the URL:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;javascript&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;plausible_ignore&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's the same code as the code that should be run on desktops,
but prefixed with &lt;code&gt;javascript:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But it doesn't work on my iPad.
I don't know about Android devices;
you could try.&lt;/p&gt;
&lt;h3 id=&quot;what-does-work-a-bookmarklet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#what-does-work-a-bookmarklet&quot;&gt;What does work: a bookmarklet&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A bookmark with the location set to a &lt;code&gt;javascript:&lt;/code&gt; URL
is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Bookmarklet&quot; class=&quot;link link-external&quot;&gt;bookmarklet&lt;/a&gt;.
So,
create a browser bookmark
with the location set to the code from the previous section,
and then run it.
Here's how:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://apple.stackexchange.com/a/74208/406227&quot; class=&quot;link link-external&quot;&gt;How to create a bookmarklet in iOS Safari.&lt;/a&gt;
Then run it by &amp;quot;opening&amp;quot; the bookmark/bookmarklet.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://android.stackexchange.com/a/210701/342608&quot; class=&quot;link link-external&quot;&gt;How to create and run a bookmarklet in Android Chrome.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that
&lt;a href=&quot;https://github.com/mozilla-mobile/firefox-ios/issues/5626&quot; class=&quot;link link-external&quot;&gt;Firefox for iOS doesn't support bookmarklets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I confirmed that the bookmarklet worked
by looking at my site's analytics;
my own visits from my iPad were not counted anymore.&lt;/p&gt;
&lt;p&gt;You can make the bookmarklet a bit friendlier
by showing an alert box after setting the &lt;code&gt;localStorage&lt;/code&gt; item:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;javascript&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;plausible_ignore&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'OK'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you don't have to wonder whether the bookmarklet was run or not.&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;If you want to run code in a browser's console on an Android device,
see these articles for pointers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/web/tools/chrome-devtools/remote-debugging&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Get Started with Remote Debugging Android Devices&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Debugging_Firefox_for_Android_with_WebIDE&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Debugging Firefox for Android with WebIDE&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;See
&lt;a href=&quot;https://www.browserstack.com/guide/how-to-debug-on-iphone&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;How to Debug on iPhone Safari&lt;/em&gt;&lt;/a&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-get-components-html-without-mounting-in-mithriljs/</id><title>How to get component's HTML without mounting in Mithril.js</title><link href="https://mtsknn.fi/blog/how-to-get-components-html-without-mounting-in-mithriljs/" /><published>2021-02-10T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mithril.js"></category><content type="html">&lt;p&gt;Create a &lt;code&gt;DocumentFragment&lt;/code&gt;
and render the component to it.
Then there's no need to mount the component to the DOM.&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;view&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&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; fragment &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;DocumentFragment&lt;/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;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fragment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;m&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 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;fragment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firstChild&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Element object&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;fragment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firstChild&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;outerHTML&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Just the HTML: `&amp;lt;div class=&quot;foo&quot;&gt;bar&amp;lt;/div&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBGADGgNCAZhBAzsgNqgB2AhmIkiAHQBWR2AxgPZkAu8XyI7ZApwAEAQQAO44QF5hwADplhwgG4R4AdyTCAFAEoZAPmFgdAcjo42bM5mFmARhQBOZvZkUBfRYoFDhOM4UAObUXDLCZJrCACJsLACuYZwAYkGhPJz6imB0zjxQ8M46gSHJdqYS4np6PmR+bAh0sGzBJenJlhDOQgDCABb4ULVkAPSj0sYAogjJwmwODPAsnHUNTS1tpRlcXT2cA0PCEIKcFPXwbDjCM-DJI+OTwpzOCfBrHASN8M2t7WWZPZ9QawKB0NgJbjOAASABUALIAGQeE2MACkEv5OP14MI4UjtAADAA8UAgKmELFgFAIBGk8lw1gZhiczmJozJKkMhMUIGwBHgCBWEE+fBQABYkOKABwgTwAXWwsBOAGsiEhSCBKNQ+JBsc58HyQAlnLA+P1OJxxAQkOMEmRxCrgnR2GBRnr+gbYAABABMdDQdHF7og+vwdEgZEYzBAnAAnuIaCACCwDeJOHL5Z4gA&quot; class=&quot;link link-external&quot;&gt;Test the code on flems.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;DocumentFragment&lt;/code&gt; on MDN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/coding-svg-icons-by-hand/</id><title>Coding SVG icons by hand</title><link href="https://mtsknn.fi/blog/coding-svg-icons-by-hand/" /><published>2021-02-05T12:00:00+03:00</published><updated>2021-10-20T12:00:00+03:00</updated><category term="SVG"></category><content type="html">&lt;p&gt;Creating icons and simple figures by handcrafting SVG code
is not as hard as it sounds.&lt;/p&gt;
&lt;p&gt;Aleksandr Hovhannisyan
has written a good primer on the topic called
&lt;a href=&quot;https://www.aleksandrhovhannisyan.com/blog/svg-tutorial-how-to-code-svg-icons-by-hand/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;SVG Tutorial: How to Code SVG Icons by Hand&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's a quick
&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Moomin_characters#Moomintroll&quot; class=&quot;link link-external&quot;&gt;Moomintroll&lt;/a&gt;
that I created using my new and refreshed SVG skills:&lt;/p&gt;
&lt;svg viewBox=&quot;0 0 24 24&quot; class=&quot;mx-auto my-8 stroke-current w-1/2&quot; style=&quot;stroke-linecap: round; stroke-linejoin: round;&quot; role=&quot;img&quot; aria-label=&quot;A simple handcrafted SVG icon of Moomintroll.&quot;&gt;
  &lt;path d=&quot;M 1 23 s 3 -35.5 7 -16 h 3 s 3 -15 5 3 a 7 6 0 1 1 -7 8&quot; fill=&quot;none&quot; /&gt;
  &lt;circle cx=&quot;8&quot; cy=&quot;12&quot; r=&quot;2&quot; fill=&quot;none&quot; stroke-width=&quot;0.5&quot; /&gt;
  &lt;circle cx=&quot;8.5&quot; cy=&quot;11.5&quot; r=&quot;0.5&quot; /&gt;
  &lt;circle cx=&quot;13&quot; cy=&quot;12&quot; r=&quot;2&quot; fill=&quot;none&quot; stroke-width=&quot;0.5&quot; /&gt;
  &lt;circle cx=&quot;13.5&quot; cy=&quot;11.5&quot; r=&quot;0.5&quot; /&gt;
&lt;/svg&gt;
&lt;p&gt;Code:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-xml bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;svg&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;viewBox&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;0 0 24 24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;style&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;
    stroke: currentColor;
    stroke-linecap: round;
    stroke-linejoin: round;
  &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 comment&quot;&gt;&amp;lt;!-- Body --&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;path&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;d&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;
      M 1 23
      s 3 -35.5 7 -16
      h 3
      s 3 -15 5 3
      a 7 6 0 1 1 -7 8
    &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;fill&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;none&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 comment&quot;&gt;&amp;lt;!-- Left eye --&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;circle&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cx&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;8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;   &lt;span class=&quot;token attr-name&quot;&gt;cy&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;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;   &lt;span class=&quot;token attr-name&quot;&gt;r&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;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;   &lt;span class=&quot;token attr-name&quot;&gt;fill&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;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&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;0.5&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;circle&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cx&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;8.5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cy&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;11.5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;r&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;0.5&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 comment&quot;&gt;&amp;lt;!-- Right eye --&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;circle&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cx&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;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;   &lt;span class=&quot;token attr-name&quot;&gt;cy&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;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;   &lt;span class=&quot;token attr-name&quot;&gt;r&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;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;   &lt;span class=&quot;token attr-name&quot;&gt;fill&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;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&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;0.5&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;circle&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cx&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;13.5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cy&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;11.5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;r&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;0.5&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;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#cubic_b%C3%A9zier_curve&quot; class=&quot;link link-external&quot;&gt;smooth cubic Bézier curves&lt;/a&gt;
(not covered in Aleksandr's article)
which required some trial and error.
But look how lovely he is!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.aleksandrhovhannisyan.com/blog/svg-tutorial-how-to-code-svg-icons-by-hand/&quot; class=&quot;link link-external&quot;&gt;Read Aleksandr's SVG Tutorial and start coding icons by hand!&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-debounce-events-in-mithriljs/</id><title>How to debounce events in Mithril.js</title><link href="https://mtsknn.fi/blog/how-to-debounce-events-in-mithriljs/" /><published>2021-02-04T12:00:00+03:00</published><updated>2021-10-26T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mithril.js"></category><content type="html">&lt;p&gt;Disable auto-redraw with &lt;code&gt;event.redraw = false&lt;/code&gt;
and use a timeout.&lt;/p&gt;
&lt;p&gt;Disabling auto-redraw is mentioned
on the &lt;a href=&quot;https://mithril.js.org/autoredraw.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Auto-redraw system&lt;/em&gt; page in Mithril docs&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mithril automatically redraws after DOM event handlers that are defined in a Mithril view.
You can disable an auto-redraw for specific events by setting &lt;code&gt;e.redraw&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Example using an &lt;code&gt;oninput&lt;/code&gt; event:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; timeout
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'25'&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oninput&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 punctuation&quot;&gt;{&lt;/span&gt;
    e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;redraw &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Update state because we are using a controlled component&lt;/span&gt;
    value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value

    &lt;span class=&quot;token function&quot;&gt;clearTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    timeout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Do something more here if needed&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Plus probably redraw manually&lt;/span&gt;
      m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;redraw&lt;/span&gt;&lt;span class=&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 number&quot;&gt;1000&lt;/span&gt;&lt;span class=&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;view&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'input[type=text]'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; oninput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&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;// Updating of this value is debounced&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'p'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&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;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgCsEAaEAYwHs0AXGWvKtOGgAgEEAHT1gXlYAUASj4A+VsAA6aVq1hsaEHJQCuNabPmsAbhigqYfVgHIATAFZj0jazAq05RdVbUIaTmoEwRUmbNYw+ABOMAAmQRgA7kZgenAw1n6yuvqG-IHkKkEhtAAqGEEA5jA0+CkGif6s5LAFuUowqjQCispqQjayrY1qRvE09W3NWMFhEZEkrACMAAxzHX4AvpWsITRZMr5V2hAwkYiCIrziyJ3+WALGbh40yDQAnpwwvHQAHjQAusaTwC5o12pJuVDIshCQzrILsZON9WABZDA0AAW+DgAEcgs1gUIFlUPjZlmhCdIRlhVLQBKFKJkcLR8AAjSihe6TLicBYgMhULCcaAwIJINAqKBQMjxWCOCDUBCIECmKaIUwAdhAiw+ZCgbgA1jLUCBMDg8FgIMigtBOSAslA8EiaDROHBEAB6J32Thawr4blO42m6AAAVM+Bm+AALD6TUizVB8Ma0ERSCAHk88HByGbODRVR9FkA&quot; class=&quot;link link-external&quot;&gt;Test the code on flems.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgCsEAaEAYwHs0AXGWvKtOGgAhYztYF5XgAdNK1bZKAV1qJWAJhKDhABwBOEcjCkBGAAxyhrGpRoYoUgBQBKHgD55w1qY518oiWwBU7I0+WqY5-AYAMpTkxjAAyjQqaADmpgDk9PEkfLZ2ngCesFLx5GJKSvTkGclpdnkFRRk5AKrhACKlesIAvua6LYKCTCysAJJoCmJsvBbWqXoA9JOsACoAFhBwrFRiUAAmrABGMKzibJRg+vO7A0NsVFgK1PRsGMsA7jBQUADcttPH9CLsELGw+ggOH2rAe4g2212cHmGEKmy2GREL36g2GK0oVxutDgtlgbBoQJg+y6ejAEnIBOoezQf3Opj8E3SMHwcKUGAePFYYGMcBgZUcMGQzIqhVos1hMRgNHwmBwAF1OcL8qKaOKlJLpQA3YxiPloMrkWCw2aE-amAnA4bmMoWolo3i81Wm4amLAsmDrNkPFIAVi0Wmtek6+r0hRo+SEAmarE1EBgDzMwBENCicCkSdluxarDa1jKwiwCSgGB2UGSrGQ+bshfi+GLpfLmZS8UQ8XaVYLCVpw2QNAyChg3DoAA8aHLyxnsDAUtRuzQUtqoLqpALkJmFW1dOlhHL20HBMHutRegBBBQKTlR4Sx+NmSzcGzRmvrCCa8uV6Ods7DFKTnA5FxaHiHM923VhC2-ec+FYTMch8NRgM3Ktn1fcsazrEtnnLeIDCMEw2xSGs4AUDA0HLAUAkMYwLHMUC7F3DoSTdLBxFoUx1hCMQcFofAtkodYMhSM8FEDEAyEuBRoBgJQkDQNYoDIXlYApCBjzwAAWDREGkAB2EAWhIdApzwfByDgUgKGoOgGEQEB62eRlWBfYji2qbYoBCABrd40GDDDS0c5yFFcqQ-igP4YAAWi2DzyG82wHggdYaHmKQdJ9BRhx8loxJAJSYBUtTbJ9RANA0fS5TIcK0E8hAUCMnA8CwCAUpUKBcvydrbPmFMFDTaYJAUTyYlMjFJma1roAAAWkfAtHwdTxpa+Y2vwZq0CICy+wHPA4HIFQFBoCqWiAA&quot; class=&quot;link link-external&quot;&gt;Another example on flems.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm not sure how much I like this solution
because it feels like it's not proper debouncing.
What if a global auto-redraw is triggered elsewhere?
It might be a problem in some cases.&lt;/p&gt;
&lt;p&gt;Can you think of a better way to debounce events in Mithril.js?
Lemme know!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-nest-selectors-in-mithriljs-for-extra-brevity/</id><title>How to nest selectors in Mithril.js for extra brevity</title><link href="https://mtsknn.fi/blog/how-to-nest-selectors-in-mithriljs-for-extra-brevity/" /><published>2021-02-02T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mithril.js"></category><content type="html">&lt;p&gt;&lt;code&gt;m.nest('ul &amp;gt; li', 'Item')&lt;/code&gt;
can be achieved with &lt;code&gt;reduceRight()&lt;/code&gt;.&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;nest&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;selector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&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; tags &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; selector&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;'&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; innermost &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&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;pop&lt;/span&gt;&lt;span class=&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;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduceRight&lt;/span&gt;&lt;span class=&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;child&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tag&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 function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; child&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; innermost&lt;span class=&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;// Usage:&lt;/span&gt;
m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;nest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul.foo &gt; li.bar &gt; a[target=_blank]'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &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 string&quot;&gt;'Link'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The same as:&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul.foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li.bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a[target=_blank]'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &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 string&quot;&gt;'Link'&lt;/span&gt;&lt;span class=&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;// Output in both cases:&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;ul&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;foo&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 plain-text&quot;&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;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;bar&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 plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;target&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;_blank&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;...&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 plain-text&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgCsEAaEAYwHs0AXGWvLfNeGgAgF42AKOGWcjUoAnEm3wSMwgOZwAlJwB8bYAB00bNlTRx2NDLM5s+AocPxwADlAg1uAckX256zdt1sIaFsKyUPXFjc+rL4lpSW3HL4NMIQQXJiEvhSsi4abMIwNACuwhohcPhZACY55DAAShDSABZ2rpo85LXQJWIhChzKQSExcQliLW2JjZpePn66jekAvurq7uy1WWBG9vU0lnCIAPS7ZeQA1vhUWLv2C2hLbACClpZGahkAbhAwAO6IPF3KyGNsJgsXQOR7KXTCajSNjKGBYexiewAGS8RzgzhIAKBrFBMLYOSgCLY-wyTUBzBx9hseIwyBWMDAHAAxABdIn2AASlBwGIBmmxIKpEBpyH0MmyHAA+gAjKAYNBHNliYBselrWaIgAi5SO2uOAHFKLzSWwWaMMiz1PM0OomH4crRuCVKOQcjhaPhpZQSgBPMT3SzpEBkEwwQQQagIRAgABMAEZEDGAOwgWYssg2BVR1AgTA4Ri2FbQYMgPJQPCbbZ7XYOyxHaSnbm7LCFuJQAACMfwAAZ8AAWZut6D4FtoIikEA0H2WXDRuDkOKWGiplmzIA&quot; class=&quot;link link-external&quot;&gt;Test the code on flems.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cleaner&lt;/li&gt;
&lt;li&gt;clearer&lt;/li&gt;
&lt;li&gt;cooler!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#source&quot;&gt;Source&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fuzetsu/microh/pull/1&quot; class=&quot;link link-external&quot;&gt;Original code on GitHub&lt;/a&gt;,
by &lt;a href=&quot;https://github.com/fuzetsu&quot; class=&quot;link link-external&quot;&gt;fuzetsu (Daniel Loomer)&lt;/a&gt;.
Variables renamed on this page for clarity.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gitter.im/mithriljs/mithril.js?at=5c9414758126720abc202d2b&quot; class=&quot;link link-external&quot;&gt;Earlier version on Mithril's Gitter room&lt;/a&gt;,
also by fuzetsu.
Here the array is looped twice (&lt;code&gt;map()&lt;/code&gt; + &lt;code&gt;reduceRight()&lt;/code&gt;),
whereas in the newer version (on this page)
there's only one loop (&lt;code&gt;reduceRight()&lt;/code&gt;).&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/lazy-and-greedy-quantifiers-in-regex/</id><title>Lazy and greedy quantifiers in regular expressions</title><link href="https://mtsknn.fi/blog/lazy-and-greedy-quantifiers-in-regex/" /><published>2021-01-29T12:00:00+03:00</published><updated>2022-04-10T12:00:00+03:00</updated><category term="Regular expressions"></category><content type="html">&lt;p&gt;Greedy quantifiers (the default, e.g. &lt;code&gt;*&lt;/code&gt;) match as much as possible.
Lazy quantifiers (e.g. &lt;code&gt;*?&lt;/code&gt;) match as little as possible.&lt;/p&gt;
&lt;h2 id=&quot;greedy-quantifiers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#greedy-quantifiers&quot;&gt;Greedy quantifiers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Greedy quantifiers keep looking until the condition is not satisfied.
They match as much as possible.&lt;/p&gt;
&lt;p&gt;Quantifiers are greedy by default.&lt;/p&gt;
&lt;h2 id=&quot;lazy-quantifiers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#lazy-quantifiers&quot;&gt;Lazy quantifiers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lazy quantifiers stop looking when the condition is satisfied.
They match as little as possible.&lt;/p&gt;
&lt;p&gt;Quantifiers can be made lazy by appending a question mark.&lt;/p&gt;
&lt;h2 id=&quot;table-of-quantifiers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#table-of-quantifiers&quot;&gt;Table of quantifiers&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Greedy quantifier&lt;/th&gt;
&lt;th&gt;Lazy quantifier&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;zero or more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;one or more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;??&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;zero or one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{n}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{n}?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;exactly n&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{n,}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{n,}?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;n or more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{n,m}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{n,m}?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;between n and m&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;example-getting-the-name-of-an-html-tag&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-getting-the-name-of-an-html-tag&quot;&gt;Example: getting the name of an HTML tag&lt;/a&gt;&lt;/h2&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; html &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'&amp;lt;div&gt;foo&amp;lt;/div&gt;'&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Greedy&lt;/span&gt;
html&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&amp;lt;.+&gt;&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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; '&amp;lt;div&gt;foo&amp;lt;/div&gt;'&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Lazy&lt;/span&gt;
html&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&amp;lt;.+?&gt;&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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; '&amp;lt;div&gt;'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see,
the greedy quantifier is too greedy in this case,
whereas the lazy quantifier matches just enough but not too much.
It's like smart laziness.
Nice!&lt;/p&gt;
&lt;h3 id=&quot;alternative&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#alternative&quot;&gt;Alternative&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes an alternative is to use a negated character class:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;html&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&amp;lt;[^&gt;]+&gt;&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 number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; '&amp;lt;div&gt;'&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case the result is the same as when using the lazy quantifier,
but the performance is better because
&lt;a href=&quot;https://stackoverflow.com/a/3075532/1079869&quot; class=&quot;link link-external&quot;&gt;&amp;quot;the negated character class can only match one way for a given input.&amp;quot;&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/formatting-lists-in-js/</id><title>Formatting lists with JavaScript's `Intl.ListFormat`</title><link href="https://mtsknn.fi/blog/formatting-lists-in-js/" /><published>2021-01-29T12:00:00+03:00</published><updated>2021-10-28T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Pass an array of strings
and get back a string with the array items separated by commas,
except with the last comma replaced with the word &amp;quot;and&amp;quot; or &amp;quot;or.&amp;quot;
Like &amp;quot;item 1, item 2 and item 3.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;using-locales&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#using-locales&quot;&gt;Using locales&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Intl.ListFormat&lt;/code&gt;&lt;/a&gt;
enables &amp;quot;language-sensitive list formatting,&amp;quot;
so you can use different locales:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; list &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;'Ham'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Spam'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Eggs'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* en-US */&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en-US'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'long'&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;'conjunction'&lt;/span&gt;&lt;span class=&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;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Ham, Spam, and Eggs&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en-US'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'short'&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;'disjunction'&lt;/span&gt;&lt;span class=&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;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Ham, Spam, or Eggs&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* en-GB */&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en-GB'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'long'&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;'conjunction'&lt;/span&gt;&lt;span class=&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;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Ham, Spam and Eggs&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en-GB'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'short'&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;'disjunction'&lt;/span&gt;&lt;span class=&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;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Ham, Spam or Eggs&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* ja-JP */&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ja-JP'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'long'&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;'conjunction'&lt;/span&gt;&lt;span class=&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;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Ham、Spam、Eggs&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ja-JP'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'short'&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;'disjunction'&lt;/span&gt;&lt;span class=&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;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Ham、Spam、またはEggs&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how the &lt;code&gt;en-US&lt;/code&gt; locale uses
&lt;a href=&quot;https://en.wikipedia.org/wiki/Serial_comma&quot; class=&quot;link link-external&quot;&gt;Oxford commas&lt;/a&gt;
and &lt;code&gt;en-GB&lt;/code&gt; does not.&lt;/p&gt;
&lt;h2 id=&quot;formatting-to-parts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#formatting-to-parts&quot;&gt;Formatting to parts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There's also a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/formatToParts&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;formatToParts()&lt;/code&gt; method&lt;/a&gt;
that &amp;quot;returns an Array of objects representing the different components
that can be used to format a list of values in a locale-aware fashion&amp;quot;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; list &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;'Ham'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Spam'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Eggs'&lt;/span&gt;&lt;span class=&quot;token punctuation&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;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en-US'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'long'&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;'disjunction'&lt;/span&gt;&lt;span class=&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;formatToParts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Ham' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'literal', value: ', ' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Spam' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'literal', value: ', or ' }, // Oxford comma 👀&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Eggs' },&lt;/span&gt;
&lt;span class=&quot;token comment&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;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'en-GB'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'short'&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;'disjunction'&lt;/span&gt;&lt;span class=&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;formatToParts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Ham' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'literal', value: ', ' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Spam' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'literal', value: ' or ' }, // No Oxford comma&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Eggs' },&lt;/span&gt;
&lt;span class=&quot;token comment&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;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ListFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ja-JP'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'short'&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;'disjunction'&lt;/span&gt;&lt;span class=&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;formatToParts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Ham' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'literal', value: '、' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Spam' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'literal', value: '、または' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     { type: 'element', value: 'Eggs' },&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm &lt;a href=&quot;https://github.com/mtsknn/mtsknn.fi/pull/29&quot; class=&quot;link link-external&quot;&gt;using &lt;code&gt;formatToParts()&lt;/code&gt; on this site to format lists of tag links&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#browser-support&quot;&gt;Browser support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://caniuse.com/mdn-javascript_builtins_intl_listformat&quot; class=&quot;link link-external&quot;&gt;Browser support of &lt;code&gt;Intl.Listformat&lt;/code&gt;&lt;/a&gt;
is nicely green,
though Safari and iOS Safari have only recently (April 2021)
added support for &lt;code&gt;Intl.ListFormat&lt;/code&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/episerver-tinymce-react/</id><title>Episerver + TinyMCE + React = uh oh!</title><link href="https://mtsknn.fi/blog/episerver-tinymce-react/" /><published>2021-01-29T12:00:00+03:00</published><updated>2021-01-29T12:00:00+03:00</updated><category term="Episerver"></category><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;Thoughts on how to efficiently use React
to render Episerver blocks
embedded in TinyMCE fields.&lt;/p&gt;
&lt;p&gt;This week at work
I was pondering how to mount a React component to a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;
whose contents are defined using the &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt; prop.
Sounds ugly,
and it is,
but hear me out:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.episerver.com/&quot; class=&quot;link link-external&quot;&gt;Episerver (.NET CMS)&lt;/a&gt;
uses the &lt;a href=&quot;https://www.tiny.cloud/&quot; class=&quot;link link-external&quot;&gt;TinyMCE editor&lt;/a&gt;
for rich text editing
and allows drag-and-dropping &amp;quot;blocks&amp;quot; (reusable pieces of content)
into TinyMCE fields.
By default,
blocks are rendered as empty &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s,
like this (simplified example):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Normal content&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-epi-block-id&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;123&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;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  More normal content.
  Block inside a paragraph:
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-epi-block-id&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;456&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;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  And more text.
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now,
I &lt;em&gt;could&lt;/em&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;render the HTML as-is,&lt;/li&gt;
&lt;li&gt;retrieve the blocks' data using Ajax requests after the component has been mounted,&lt;/li&gt;
&lt;li&gt;and then mount other React components to the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But I don't want to,
because that would be slow
and incur an extra HTTP request &lt;em&gt;per each block&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I'm thinking of including the blocks' data in the HTML
before sending it to the front-end:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Normal content&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-epi-block&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;'&lt;/span&gt;{ &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;: 123, &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;blockType&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;: &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;FooBlock&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;, &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;: &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Hello block&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;, ... }&lt;span class=&quot;token punctuation&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  More normal content.
  Block inside a paragraph:
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-epi-block&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;'&lt;/span&gt;{ &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;: 456, &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;blockType&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;: &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;BarBlock&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;, &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;: &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Another block&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;, ... }&lt;span class=&quot;token punctuation&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  And more text.
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I could use &lt;code&gt;JSON.parse()&lt;/code&gt;
to turn those JSON attributes into props objects.
Mounting React components to those &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s
could be done as suggested in these Stack Overflow answers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/44688007/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;React: using React component inside of dangerouslySetInnerHTML&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/45712853/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Render custom React component within HTML string from server&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like I said: ugly!
And still just a theory.
But necessary.
We shall see later if this feasible.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-pretty-print-json-in-javascript/</id><title>How to pretty print JSON in JavaScript</title><link href="https://mtsknn.fi/blog/how-to-pretty-print-json-in-javascript/" /><published>2021-01-28T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Run &lt;code&gt;JSON.stringify(object, null, 2)&lt;/code&gt;.
Adjust the number for a different level of indentation.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; object &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;foo&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;ham&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;spam&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 number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&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 constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// {&quot;foo&quot;:&quot;bar&quot;,&quot;ham&quot;:{&quot;spam&quot;:[10,20]}}&lt;/span&gt;

&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// {&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   &quot;foo&quot;: &quot;bar&quot;,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   &quot;ham&quot;: {&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     &quot;spam&quot;: [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       10,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       20&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     ]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   }&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// }&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify&quot; class=&quot;link link-external&quot;&gt;Read more about &lt;code&gt;JSON.stringify()&lt;/code&gt; on MDN&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/converting-a-path-into-cumulative-segments-in-javascript/</id><title>3 ways to convert a path into cumulative segments in JavaScript</title><link href="https://mtsknn.fi/blog/converting-a-path-into-cumulative-segments-in-javascript/" /><published>2021-01-26T12:00:00+03:00</published><updated>2021-10-26T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Regular expressions"></category><content type="html">&lt;p&gt;How to convert
&lt;code&gt;'/foo/bar/baz/'&lt;/code&gt;
into an array of
&lt;code&gt;'/'&lt;/code&gt;, &lt;code&gt;'/foo/'&lt;/code&gt;, &lt;code&gt;'/foo/bar/'&lt;/code&gt;, and &lt;code&gt;'/foo/bar/baz/'&lt;/code&gt;.
Example use case: building breadcrumb navigations.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Given a path like &lt;code&gt;/foo/bar/baz/&lt;/code&gt;,
we want to convert it into an array like this:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Starting from the left,
each array item grows until the next forward slash in the path.
The path could be a directory path or an URL pathname.&lt;/p&gt;
&lt;p&gt;I needed this when creating breadcrumb navigations for this website,
so the paths were URL pathnames.&lt;/p&gt;
&lt;h2 id=&quot;the-3-solutions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-3-solutions&quot;&gt;The 3 solutions&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;split-and-reduce&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#split-and-reduce&quot;&gt;Split and reduce&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was my initial solution:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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;
  path
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Drop empty strings caused by the splitting&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;segments&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; segment&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; previous &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; segments&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;segments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &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;
        segments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;previous&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;segment&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 keyword&quot;&gt;return&lt;/span&gt; segments
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simplistic, but works.&lt;/p&gt;
&lt;p&gt;One caveat though:
the last array item will have a trailing slash
even if the input string doesn't have a trailing slash.
This may or may not be a problem in your case.&lt;/p&gt;
&lt;p&gt;If you want to omit the first array item (the slash):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;set &lt;code&gt;'/'&lt;/code&gt; as the default value of &lt;code&gt;previous&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;change the initial array from &lt;code&gt;['/']&lt;/code&gt; to &lt;code&gt;[]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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 prefix unchanged&quot;&gt; &lt;/span&gt;  path
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;segments&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; segment&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&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; previous &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; segments&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;segments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; previous &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; segments&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;segments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &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 operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;        segments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token 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;previous&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;segment&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 prefix unchanged&quot;&gt; &lt;/span&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; segments
&lt;span class=&quot;token prefix unchanged&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&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBGADGgNCAZhBAzsgNqgB2AhmIkiAHQBWR2AxgPZkAu8XyI7ZApwAEANxTCAvMIAUABwqcAFgEopAPgA6ZYcIXLtu3XQJzYETjIDkAeisrDRunljcATjIBCbNggpk1GxthABE3NjlheDA5TgBPYSE3CDIAcwJhFgoAVwJ4KGEAIwTleESzC04U1MdjN3zslngZWqMZPNTqLgJMRPhOnk41SXVhYFajTI4hPXrRCDZcqT6B7uIOrs4COgQ05WEAWmEUAF0Jow3B7blcpRkAAwASYDk5hdyAX2fLrg+be4cOkmRnqnGybh0Py25w+mHOxFsVjOQN0gO0AhmogATMt5IpVBpHPolK0TBVLIjAZNnPh3F4fH4AqT6lBGs12v1Nj0VpthqNxiijBiRK94PNFhlpFCCOtOVcdjxUvsjqdhAAfNXCRHnaV0G4EO5PF5vCVfYBQv4A86g8GQuXdVqw4TEE5osgY3zwHZsVLWcS9MhsYScNwUfDVRKwCgGpBWXriaw2HA+GyFChuVMUABe9kBHoQ3t9Vn9wgA7sEQ2HzGlI9GlLH4yhE8m2JmM2ms3YVG7817YD6-ViA0HK+GawQozG42Isc2U2n29nc+jpp7C4PeuXg6Gx6la1P47PbC225nO8uyCBsHkECwqtM+FiAOxIACsAA4QB8Th8gA&quot; class=&quot;link link-external&quot;&gt;Test the split and reduce solution on flems.io&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;map-with-a-bit-of-curry&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#map-with-a-bit-of-curry&quot;&gt;Map with a bit of curry&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Who doesn't like curry?
It makes chicken taste so much better.
&lt;a href=&quot;https://javascript.info/currying-partials&quot; class=&quot;link link-external&quot;&gt;Currying&lt;/a&gt;
also makes this cool solution possible:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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 function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&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 parameter&quot;&gt;value&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;acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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 keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cumulativePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&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; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait, what?
Let's see how it works
by adding console loggings:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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 function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&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 parameter&quot;&gt;value&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 punctuation&quot;&gt;{&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&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 punctuation&quot;&gt;(&lt;/span&gt;acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cumulativePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&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;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; { acc: '/',         value: 'foo' }&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   { acc: '/foo/',     value: 'bar' }&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   { acc: '/foo/bar/', value: 'baz' }&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The outer function's &lt;code&gt;acc&lt;/code&gt; parameter acts as an accumulator,
like when using an array reducer.&lt;/p&gt;
&lt;p&gt;We are reassigning the parameter,
which by the way violates the
&lt;a href=&quot;https://eslint.org/docs/rules/no-param-reassign&quot; class=&quot;link link-external&quot;&gt;ESLint rule &lt;code&gt;no-param-reassign&lt;/code&gt;&lt;/a&gt;.
This is not a problem per se,
but it's a potential source of confusion.&lt;/p&gt;
&lt;p&gt;We could avoid reassigning the parameter
by getting rid of the currying
and creating an &lt;code&gt;acc&lt;/code&gt; variable:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&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 parameter&quot;&gt;value&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&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&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&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;acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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 prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cumulativePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There's one more oddity:
the &lt;code&gt;cumulativePath&lt;/code&gt; function's return statement contains an addition assignment.
This violates the
&lt;a href=&quot;https://eslint.org/docs/rules/no-return-assign&quot; class=&quot;link link-external&quot;&gt;ESLint rule &lt;code&gt;no-return-assign&lt;/code&gt;&lt;/a&gt;,
which again is not a problem per se but is confusing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Return_value_and_chaining&quot; class=&quot;link link-external&quot;&gt;Assignment operators have return values&lt;/a&gt;,
meaning that these two are effectively equivalent:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&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 parameter&quot;&gt;value&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;acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&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 parameter&quot;&gt;value&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;
  acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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 keyword&quot;&gt;return&lt;/span&gt; acc
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all the magic stripped out,
here's the full function:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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;let&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&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;
    acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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 keyword&quot;&gt;return&lt;/span&gt; acc
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cumulativePath&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or maybe in a clearer form:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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;let&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&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;
      acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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 keyword&quot;&gt;return&lt;/span&gt; acc
    &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it's quite easy to see what's happening.
Though it's not as cool anymore, is it?&lt;/p&gt;
&lt;p&gt;This is also very similar to the &lt;a href=&quot;#split-and-reduce&quot; class=&quot;link link-anchor&quot;&gt;split and reduce solution&lt;/a&gt;.
Both solutions have the same caveat:
the last array item will have a trailing slash
even if the input string doesn't have a trailing slash.&lt;/p&gt;
&lt;p&gt;Here's one way to have a slash as the first item of the resulting array:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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 prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;cumulativePath&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&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 parameter&quot;&gt;value&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;acc &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;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&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&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 string&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;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;    path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt;&lt;span class=&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;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cumulativePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&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 prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBGADGgNCAZhBAzsgNqgB2AhmIkiAHQAWALmLCNgMYD2ZT8vyECAC+mclRr0AVkU48+A2tzIEmAAgBuKNQF41ACgAOFJgwCUugHxrgAHTJq1y1U4CuYV7BMQN8AAomDLoGFBwcFjrW+hoUsK7wEVGhHGoA1HoABgAkwDFx8MIA9Blm9o4ATvBMruUOxqZ0BIawEEz6AOSF7WZ0eLB85foAQlxcCBRkPWAUhvoc7p7evgGmHV1mpWTC9vbO6hoATMFGgYk2ZU48LvMeXkw+-oHHyWfRsfGvyWmZOXnxRSULpVqrU1MROu0ALp0ZQcEwnBpNFptCE9PoDYajcaTOjTWY3Rb3ZaBNbdDb2bZkXZXMbwOiwLgAcw6WkwajIXDUTHKFHwEDIjLUBC8BAYSHabK0axwo0KACMKOV5RQAF5k6kqWn0pkslBsgDuhS5PL5AqFIrFEs0KGlsoVSoVKvWmw1BC1DOZ7UObI5xt5LTNwooovFkoOtq4yodqvVZGc7p1XoOBqN3P9-MFQZDVsOEajyqdsfYIG4YEM+Hg5WQZE8sGwBHgCA49yughQABYkABWAAcIjEIEo1EEMIIshL8n4TEEIkhwiAA&quot; class=&quot;link link-external&quot;&gt;Test the map and curry solution on flems.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;All credit of the cleverness goes to
&lt;a href=&quot;https://stackoverflow.com/a/55259065/1079869&quot; class=&quot;link link-external&quot;&gt;Nina Scholz's post on Stack Overflow&lt;/a&gt;
which I found via
&lt;a href=&quot;https://stackoverflow.com/a/55261098/1079869&quot; class=&quot;link link-external&quot;&gt;another post on Stack Overflow&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;regex-to-the-rescue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#regex-to-the-rescue&quot;&gt;Regex to the rescue&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If all you have is a hammer,
everything looks like a nail.
What I mean is that
this problem looks like it's &lt;em&gt;made&lt;/em&gt; to be solved with a regular expression!&lt;/p&gt;
&lt;p&gt;Basically,
when we encounter a forward slash or the end of the string (&lt;code&gt;(\/|$)&lt;/code&gt;),
we want to capture it
plus everything before that (&lt;code&gt;.*&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We could try something like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;.*(\/|$)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/bar/baz/', '']&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/bar/baz', '']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or a &lt;a href=&quot;/blog/lazy-and-greedy-quantifiers-in-regex/&quot; class=&quot;link&quot;&gt;lazy quantifier&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;.*?(\/|$)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', 'foo/', 'bar/', 'baz/', '']&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', 'foo/', 'bar/', 'baz', '']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or a positive lookbehind assertion:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=.*)(\/|$)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/', '/', '/', '']&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/', '/', '']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All three regexes fail miserably
because we have to do overlapping matches,
and this is not how they are done.
Check out my previous blog post
&lt;a href=&quot;https://mtsknn.fi/blog/how-to-do-overlapping-matches-with-regular-expressions/&quot; class=&quot;link&quot;&gt;&lt;em&gt;How to do overlapping matches with regular expressions&lt;/em&gt;&lt;/a&gt;
for a walkthrough.&lt;/p&gt;
&lt;p&gt;To do overlapping matches,
we have to use &lt;code&gt;matchAll()&lt;/code&gt;
and a positive lookbehind assertion with a capturing group inside of it:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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;
  Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=(.*(\/|$)))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/&quot;, &quot;/&quot;, index: 1, input: &quot;/foo/bar/baz/&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/foo/&quot;, &quot;/&quot;, index: 5, input: &quot;/foo/bar/baz/&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/foo/bar/&quot;, &quot;/&quot;, index: 9, input: &quot;/foo/bar/baz/&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/foo/bar/baz/&quot;, &quot;/&quot;, index: 13, input: &quot;/foo/bar/baz/&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/&quot;, &quot;/&quot;, index: 1, input: &quot;/foo/bar/baz&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/foo/&quot;, &quot;/&quot;, index: 5, input: &quot;/foo/bar/baz&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/foo/bar/&quot;, &quot;/&quot;, index: 9, input: &quot;/foo/bar/baz&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;/foo/bar/baz&quot;, &quot;&quot;, index: 12, input: &quot;/foo/bar/baz&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looks good.
Let's get only the second array items,
i.e. the matches from the capturing group inside the lookbehind assertion:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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;
  Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=(.*(\/|$)))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token 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;match&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; match&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;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Egg-cellent!
As you can see,
whether the last item of the resulting array has a trailing slash
depends on whether the input string has a trailing slash.
This is better than the other two solutions;
they always include a trailing slash in the last item of the resulting array.&lt;/p&gt;
&lt;p&gt;If you want to omit the first array item (the slash),
you need to only change &lt;code&gt;.*&lt;/code&gt; to &lt;code&gt;.+&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getCumulativePathSegments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&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&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=(.*(\/|$)))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token 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;match&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; match&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=(.+(\/|$)))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token 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;match&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; match&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&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pathWithoutTrailingSlash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz'&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz/']&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pathWithoutTrailingSlash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/', '/foo/', '/foo/bar/', '/foo/bar/baz']&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['/foo/', '/foo/bar/', '/foo/bar/baz']&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBGADGgNCAZhBAzsgNqgB2AhmIkiAHQBWR2AxgPZkAu8XyI7ZApwAEANxTCAvMIAUABwqcAFgEopAPgA6ZYcICCAJwMUAnnRwG2YeYqV0wilkr2xYMgPQyA-AB5JMugAqGU1NdwAfABIVGPcAcxVMWQdOJzVJdWEUp2IUAF0VbW0BITEAJilZBWV0rR19I1NzS2tqu2znVw9vPwCAahCwqJiVeMTkx1UNLMncgqKyErYEOlg2OJkAcnEksjZhTmN8CDI44QJYCgIlJE2k8S33HDY2dwAjCgN3igAvTZjihwCMt4Kt1lsdsIAO7uA5HWAnM4XK43O5iFCPZ6vD5fD4-dz-QpkQGCEFgjbbMq7faHCjHU7nS7XW73MqYl7fXG-Qkk4ErNYU0RU6Gw2n0pFM1Gs9nYz7ffE8sggbAEeAIFicCBAvjoJAAVgAHCAAL55Y1AA&quot; class=&quot;link link-external&quot;&gt;Test the regex solution on flems.io&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;which-solution-is-the-best&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#which-solution-is-the-best&quot;&gt;Which solution is the best?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;#split-and-reduce&quot; class=&quot;link link-anchor&quot;&gt;split and reduce solution&lt;/a&gt;
might be the most straightforward solution.
It's not as elegant as the other two,
but at least it's readable.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;#map-with-a-bit-of-curry&quot; class=&quot;link link-anchor&quot;&gt;map and curry solution&lt;/a&gt;
is fancy –
actually,
it's so fancy that I still find it quite confusing.
It seems to work,
but personally I wouldn't use it.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;#regex-to-the-rescue&quot; class=&quot;link link-anchor&quot;&gt;regex solution&lt;/a&gt;
is the shortest solution,
but requires the reader to know some regex trickery.
It's also the only solution which respects the input string's trailing slash.
You could modify the other two solutions to do that too,
but they would become more complex and less readable.&lt;/p&gt;
&lt;p&gt;I'm a rebel,
so I'm using the regex solution on this website. 🤘&lt;/p&gt;
&lt;h2 id=&quot;bonus-using-for-breadcrumb-navigations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-using-for-breadcrumb-navigations&quot;&gt;Bonus: Using for breadcrumb navigations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here's a quick example using React
how the &lt;code&gt;getCumulativePathSegments()&lt;/code&gt; function
could be used for generating breadcrumb navigations:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pageNames &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-property property&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Home'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;'/foo/'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;'/foo/bar/'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'BAR'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;'/foo/bar/baz/'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'Bäz'&lt;/span&gt;&lt;span class=&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 function&quot;&gt;Breadcrumb&lt;/span&gt;&lt;span class=&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; pageUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/foo/bar/baz/'&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// or e.g. `window.location.pathname`&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getCumulativePathSegments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pageUrl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;segment&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 punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; segment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pageNames&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;segment&lt;span class=&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;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;nav&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&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;Breadcrumb&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 plain-text&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;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 punctuation&quot;&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;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&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&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&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&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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 plain-text&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;nav&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&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;Breadcrumb&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;ul&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/&lt;span class=&quot;token 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;Home&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/foo/&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;Foo&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/foo/bar/&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;BAR&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/foo/bar/baz/&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;Bäz&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&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;ul&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;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/two-types-of-skills-and-two-types-of-learning/</id><title>Two types of skills and two types of learning</title><link href="https://mtsknn.fi/blog/two-types-of-skills-and-two-types-of-learning/" /><published>2021-01-22T12:00:00+03:00</published><updated>2021-10-26T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;Expiring skills vs permanent skills
and just-in-time learning vs just-in-case learning.&lt;/p&gt;
&lt;p&gt;TL;DR of Mike Crittenden's blog post
&lt;a href=&quot;https://critter.blog/2020/08/14/learning-a-technology-you-dont-need-right-now-is-a-waste-of-time/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Learning a technology you don't need right now is a waste of time&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two types of skills:
&lt;ul&gt;
&lt;li&gt;Expiring skills: hard skills, e.g. TypeScript, React, Kubernetes&lt;/li&gt;
&lt;li&gt;Permanent skills: soft skills, e.g. attitude, discipline, charisma&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Two types of learning:
&lt;ul&gt;
&lt;li&gt;Just-in-time: learn when you need the skill/knowledge&lt;/li&gt;
&lt;li&gt;Just-in-case: learn in case you need the skill/knowledge in the future&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hard skills expire,
so learning them just-in-case is a waste of time&lt;/li&gt;
&lt;li&gt;Soft skills are permanent and compound over time,
so learning them just-in-case is wise&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is why I'm not eager to take courses
if they are about hard/expiring skills that I know I won't need in the near future.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://critter.blog/2020/08/14/learning-a-technology-you-dont-need-right-now-is-a-waste-of-time/&quot; class=&quot;link link-external&quot;&gt;Read the full blog post by Mike Crittenden&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/javascripts-date-constructor-is-bad-at-parsing-dates/</id><title>`new Date()` and `Date.parse()` are bad at parsing dates</title><link href="https://mtsknn.fi/blog/javascripts-date-constructor-is-bad-at-parsing-dates/" /><published>2021-01-22T12:00:00+03:00</published><updated>2023-06-13T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Use them only with certain date time formats,
and use a library for parsing fancy formats.&lt;/p&gt;
&lt;h2 id=&quot;they-used-to-be-discouraged&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#they-used-to-be-discouraged&quot;&gt;They used to be discouraged&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;&lt;code&gt;Date()&lt;/code&gt; constructor&lt;/em&gt; on MDN&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Parsing of date strings with the &lt;code&gt;Date&lt;/code&gt; constructor
(and &lt;code&gt;Date.parse()&lt;/code&gt;, which works the same way)
is &lt;em&gt;strongly discouraged&lt;/em&gt; due to browser differences and inconsistencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;
&lt;a href=&quot;https://github.com/mdn/content/pull/17100&quot; class=&quot;link link-external&quot;&gt;the MDN page was updated in June 2022&lt;/a&gt;.
Now the page doesn't say anymore that the &lt;code&gt;Date()&lt;/code&gt; constructor and &lt;code&gt;Date.parse()&lt;/code&gt; are &amp;quot;strongly discouraged.&amp;quot;
From the linked pull request:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think parsing ISO date strings is useful enough to not be completely discouraged.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;fancy-formats-are-poorly-supported&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fancy-formats-are-poorly-supported&quot;&gt;Fancy formats are poorly supported&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For example,
the string &lt;code&gt;&amp;quot;2021-01-10 12:47:29 UTC&amp;quot;&lt;/code&gt;
is parsed correctly on Chrome,
but results in &amp;quot;Invalid Date&amp;quot; on Firefox and iOS Safari (as of Jan 22, 2021):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 string&quot;&gt;'2021-01-10 12:47:29 UTC'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Chrome:     Sun Jan 10 2021 14:47:29 GMT+0200 (Eastern European Standard Time)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   Firefox:    Invalid Date&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   iOS Safari: Invalid Date&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;certain-formats-are-well-supported&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#certain-formats-are-well-supported&quot;&gt;Certain formats are well-supported&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Compare with a proper format
that works in all three browsers:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 string&quot;&gt;'2021-01-10T12:47:29.000Z'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Z = UTC&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Chrome:     Sun Jan 10 2021 14:47:29 GMT+0200 (Eastern European Standard Time)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   Firefox:    Sun Jan 10 2021 14:47:29 GMT+0200 (Eastern European Standard Time)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   iOS Safari: Sun Jan 10 2021 14:47:29 GMT+0200 (EET)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For proper formats,
see &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Date time string format&lt;/em&gt; on MDN&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;momentjs-vs-others&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#momentjs-vs-others&quot;&gt;Moment.js vs others&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have to parse fancy formats,
consider using a library for that.&lt;/p&gt;
&lt;p&gt;Probably don't choose Moment.js for new projects
because &lt;a href=&quot;https://momentjs.com/docs/#/-project-status/&quot; class=&quot;link link-external&quot;&gt;Moment.js is in maintenance mode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://momentjs.com/docs/#/-project-status/recommendations/&quot; class=&quot;link link-external&quot;&gt;Moment.js alternatives&lt;/a&gt; instead.
I have been satisfied with &lt;a href=&quot;https://date-fns.org/&quot; class=&quot;link link-external&quot;&gt;date-fns&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/illegal-invocations-in-js/</id><title>&quot;Illegal invocation&quot; errors in JavaScript</title><link href="https://mtsknn.fi/blog/illegal-invocations-in-js/" /><published>2021-01-22T12:00:00+03:00</published><updated>2022-04-17T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;The error is thrown when calling a function
whose &lt;code&gt;this&lt;/code&gt; keyword isn't referring to the object where it originally did,
i.e. when the &amp;quot;context&amp;quot; of the function is lost.&lt;/p&gt;
&lt;h2 id=&quot;example-problems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-problems&quot;&gt;Example problems&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I encountered the &amp;quot;illegal invocation&amp;quot; error
when calling the destructured &lt;code&gt;abort&lt;/code&gt; method of an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/AbortController&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;AbortController&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abortController &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;AbortController&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; abort &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; abortController

&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another case:
trying to implement jQuery-like shorthands for
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;document.querySelector&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;document.querySelectorAll&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelector
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelectorAll

&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'#foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(By the way:
most, if not all, modern browsers
have the &lt;code&gt;$&lt;/code&gt; and &lt;code&gt;$$&lt;/code&gt; shorthands
built into the browser's JS console.)&lt;/p&gt;
&lt;h2 id=&quot;description-of-the-error&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#description-of-the-error&quot;&gt;Description of the error&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&amp;quot;Invocation&amp;quot; is the act invoking a function,
which is the same as calling a function.
Invoke = call.&lt;/p&gt;
&lt;p&gt;An &amp;quot;illegal invocation&amp;quot; error is thrown when
&lt;strong&gt;calling a function whose &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;this&lt;/code&gt; keyword&lt;/a&gt; doesn't refer to the object where it originally did&lt;/strong&gt;.
In other words,
the original &amp;quot;context&amp;quot; of the function is lost.&lt;/p&gt;
&lt;p&gt;Chromium browsers call this error an &amp;quot;illegal invocation.&amp;quot;&lt;/p&gt;
&lt;p&gt;Firefox produces more descriptive error messages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;TypeError:
'abort' called on an object
that does not implement interface AbortController.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;TypeError:
'querySelector' called on an object
that does not implement interface Document.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So does Safari:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;TypeError:
Can only call AbortController.abort
on instances of AbortController&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;TypeError:
Can only call Document.querySelector
on instances of Document&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Node.js (v16) produces clearly the best error messages, e.g.:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;TypeError [ERR_INVALID_THIS]:
Value of &amp;quot;this&amp;quot; must be of type AbortController&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://deno.land/&quot; class=&quot;link link-external&quot;&gt;Deno&lt;/a&gt; uses V8 – the same JS engine as Chromium browsers do –
so Deno also calls the error an &amp;quot;illegal invocation.&amp;quot;&lt;/p&gt;
&lt;h3 id=&quot;manual-implementation-of-an-illegal-invocation-check&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#manual-implementation-of-an-illegal-invocation-check&quot;&gt;Manual implementation of an &amp;quot;illegal invocation&amp;quot; check&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For demonstration purposes:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; foo &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 function-variable function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token operator&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;
    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;'Calling foo.bar; `this` refers to'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; foo&lt;span class=&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;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TypeError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'Illegal invocation 🛑'&lt;/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;&lt;span class=&quot;token string&quot;&gt;'Successfully called foo.bar ✅'&lt;/span&gt;&lt;span class=&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;

foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Calling foo.bar; `this` refers to foo&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Successfully called foo.bar ✅&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; bar &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; foo
&lt;span class=&quot;token function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Calling foo.bar; `this` refers to window&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation 🛑&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bar2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bar
&lt;span class=&quot;token function&quot;&gt;bar2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Calling foo.bar; `this` refers to window&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; TypeError: Illegal invocation 🛑&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In real code,
you should use better error messages.
&amp;quot;Illegal invocation&amp;quot; is not clear.&lt;/li&gt;
&lt;li&gt;In &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode&quot; class=&quot;link link-external&quot;&gt;strict mode&lt;/a&gt;,
&lt;code&gt;this&lt;/code&gt; would be &lt;code&gt;undefined&lt;/code&gt; instead of &lt;code&gt;window&lt;/code&gt; in the error cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-does-the-this-keyword-change&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#why-does-the-this-keyword-change&quot;&gt;Why does the &lt;code&gt;this&lt;/code&gt; keyword change?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;this&lt;/code&gt; keyword in JavaScript&lt;/a&gt; is confusing!&lt;/p&gt;
&lt;p&gt;The gist is in the difference between &lt;em&gt;method invocations&lt;/em&gt; and &lt;em&gt;function invocations&lt;/em&gt;.&lt;/p&gt;
&lt;h4&gt;Method invocations&lt;/h4&gt;
&lt;p&gt;A &lt;em&gt;method&lt;/em&gt; is a function stored as a property of an object.
When invoking (i.e. calling) a method
using the dot notation or square bracket notation,
the &lt;code&gt;this&lt;/code&gt; keyword is bound to the object:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; foo &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 function&quot;&gt;bar&lt;/span&gt;&lt;span class=&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;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&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; method &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Method invocations:&lt;/span&gt;
foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; foo&lt;/span&gt;
foo&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; foo&lt;/span&gt;
foo&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;method&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; foo&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Function invocations&lt;/h4&gt;
&lt;p&gt;When invoking (i.e. calling) a function that is not the property of an object,
the &lt;code&gt;this&lt;/code&gt; keyword is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bound to the global object (&lt;code&gt;window&lt;/code&gt;) in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Sloppy_mode&quot; class=&quot;link link-external&quot;&gt;sloppy mode&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;undefined&lt;/code&gt; in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode&quot; class=&quot;link link-external&quot;&gt;strict mode&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In either mode,
the original context is lost
because the &lt;code&gt;this&lt;/code&gt; keyword doesn't refer to the object where it originally did:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; bar &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; foo
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bar2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bar
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bar3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Function invocations:&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; window (in sloppy mode) / undefined (in strict mode)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;bar2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; window (in sloppy mode) / undefined (in strict mode)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;bar3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; window (in sloppy mode) / undefined (in strict mode)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As to &lt;em&gt;why&lt;/em&gt; the context is lost –
let's quote &lt;a href=&quot;https://www.oreilly.com/library/view/javascript-the-good/9780596517748/&quot; class=&quot;link link-external&quot;&gt;Douglas Crockford's book &lt;em&gt;JavaScript: The Good Parts&lt;/em&gt;&lt;/a&gt;
(1st ed., p. 28; emphasis added):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When a function is not the property of an object,
then it is invoked as a function:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// sum is 7&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a function is invoked with this pattern,
&lt;code&gt;this&lt;/code&gt; is bound to the global object.
&lt;strong&gt;This was a mistake in the design of the language.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Sidetrack: arrow functions&lt;/h4&gt;
&lt;p&gt;The quote from the book continues
(pp. 28–29; text split into paragraphs and code block slightly edited):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Had the language been designed correctly,
when the inner function is invoked,
&lt;code&gt;this&lt;/code&gt; would still be bound to the &lt;code&gt;this&lt;/code&gt; variable of the outer function.&lt;/p&gt;
&lt;p&gt;A consequence of this error is that
a method cannot employ an inner function to help it do its work
because the inner function does not share the method's access to the object
as its &lt;code&gt;this&lt;/code&gt; is bound to the wrong value.&lt;/p&gt;
&lt;p&gt;Fortunately, there is an easy workaround.
If the method defines a variable and assigns it the value of &lt;code&gt;this&lt;/code&gt;,
the inner function will have access to &lt;code&gt;this&lt;/code&gt; through that variable.
By convention, the name of that variable is &lt;code&gt;that&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; myObject &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;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Augment myObject with a double method&lt;/span&gt;
myObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;token operator&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 keyword&quot;&gt;var&lt;/span&gt; that &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Workaround&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;helper&lt;/span&gt; &lt;span class=&quot;token operator&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;
    that&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;that&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; that&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&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;helper&lt;/span&gt;&lt;span class=&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;// Invoke helper as a function&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

myObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;double&lt;/span&gt;&lt;span class=&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;// Invoke double as a method&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;myObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nowadays you can alternatively use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot; class=&quot;link link-external&quot;&gt;arrow functions&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;myObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;token operator&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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;helper&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;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&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; &lt;span class=&quot;token keyword&quot;&gt;this&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;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;helper&lt;/span&gt;&lt;span class=&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;// Invoke helper as a function&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

myObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;double&lt;/span&gt;&lt;span class=&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;// Invoke double as a method&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;myObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 6&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Arrow functions increase the complexity around the &lt;code&gt;this&lt;/code&gt; keyword;
or reduce complexity, depending on the viewpoint.&lt;/p&gt;
&lt;p&gt;Anyhow, the &lt;code&gt;this&lt;/code&gt; keyword in JavaScript is confusing.
I personally try to avoid it.
It has many potential pitfalls,
and often there are better alternatives.&lt;/p&gt;
&lt;h2 id=&quot;three-ways-to-fix-the-error&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#three-ways-to-fix-the-error&quot;&gt;Three ways to fix the error&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here's the original, problematic example code:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abortController &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;AbortController&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; abort &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; abortController

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelector
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;querySelectorAll
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The gist of the problem is that
calling &lt;code&gt;abort&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt; or &lt;code&gt;$$&lt;/code&gt;
is a function invocation,
not a method invocation,
so the context is lost.&lt;/p&gt;
&lt;h3 id=&quot;create-a-function-that-calls-a-method&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#create-a-function-that-calls-a-method&quot;&gt;Create a function that calls a method&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As we learned above,
with a method invocation (as opposed to a function invocation),
the &lt;code&gt;this&lt;/code&gt; keyword is bound to the object.&lt;/p&gt;
&lt;p&gt;So, create an &lt;code&gt;abort&lt;/code&gt; function that calls the &lt;code&gt;abortController.abort&lt;/code&gt; method:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abortController &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;AbortController&lt;/span&gt;&lt;span class=&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; &lt;span class=&quot;token function-variable function&quot;&gt;abort&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;=&gt;&lt;/span&gt; abortController&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&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;abort&lt;/span&gt;&lt;span class=&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;// OK!&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling &lt;code&gt;abort&lt;/code&gt; is a function invocation,
but &lt;code&gt;abort&lt;/code&gt; in turn calls &lt;code&gt;abortController.abort&lt;/code&gt; using method invocation,
so the context is not lost.&lt;/p&gt;
&lt;p&gt;Similarly for &lt;code&gt;$&lt;/code&gt; and &lt;code&gt;$$&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&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 parameter&quot;&gt;selectors&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; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selectors&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 function-variable function&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 parameter&quot;&gt;selectors&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; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selectors&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'#foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK!&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK!&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(By the way:
notice how the function parameters are in the plural form:
&lt;code&gt;selectors&lt;/code&gt; instead of &lt;code&gt;selector&lt;/code&gt;.
That's because &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;document.querySelector&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;document.querySelectorAll&lt;/code&gt;&lt;/a&gt;
accept a comma-separated list of CSS selectors.)&lt;/p&gt;
&lt;h3 id=&quot;use-bind-to-change-the-this-keyword&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#use-bind-to-change-the-this-keyword&quot;&gt;Use &lt;code&gt;bind()&lt;/code&gt; to change the &lt;code&gt;this&lt;/code&gt; keyword&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A more convoluted solution is to use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Function.prototype.bind()&lt;/code&gt;&lt;/a&gt;
to set the &lt;code&gt;this&lt;/code&gt; keyword to point to the correct object:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abortController &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;AbortController&lt;/span&gt;&lt;span class=&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; abort &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; abortController&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;abortController&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 operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; $$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&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;// OK!&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'#foo'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK!&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.bar'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OK!&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There's also &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Function.prototype.apply()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Function.prototype.call()&lt;/code&gt;&lt;/a&gt;,
but they are also convoluted
because they deal with the &lt;code&gt;this&lt;/code&gt; keyword.&lt;/p&gt;
&lt;p&gt;I recommend the previous solution which doesn't deal with the &lt;code&gt;this&lt;/code&gt; parameter:
&lt;a href=&quot;#create-a-function-that-calls-a-method&quot; class=&quot;link link-anchor&quot;&gt;Create a function that calls a method&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;export-the-whole-object&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#export-the-whole-object&quot;&gt;Export the whole object&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;(Maybe an obvious solution,
but mentioning it anyway.)&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;AbortController&lt;/code&gt; case,
I originally destructured the &lt;code&gt;abort&lt;/code&gt; method
because I wanted to export only that method,
not the whole &lt;code&gt;AbortController&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you are fine with exporting the whole &lt;code&gt;AbortController&lt;/code&gt;,
calling its &lt;code&gt;abort&lt;/code&gt; method directly is fine too
(because it'll be a method invocation):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abortController &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;AbortController&lt;/span&gt;&lt;span class=&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;// In another file:&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; abortController &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'...'&lt;/span&gt;
abortController&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&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;// OK!&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This solution doesn't apply to the &lt;code&gt;$&lt;/code&gt; and &lt;code&gt;$$&lt;/code&gt; functions
because &lt;code&gt;document&lt;/code&gt; is anyway available in all modules.&lt;/p&gt;
&lt;h2 id=&quot;sources-further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#sources-further-resources&quot;&gt;Sources / Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I learned about &amp;quot;illegal invocation&amp;quot; errors via these Stack Overflow questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/9677985/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;&amp;quot;Uncaught TypeError: Illegal invocation&amp;quot; in Chrome&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/10743596/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Why are certain function calls termed &amp;quot;illegal invocations&amp;quot; in JavaScript?&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/8904782/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Uncaught TypeError: Illegal invocation in JavaScript&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I learned about the differences between method invocations and function invocations from
&lt;a href=&quot;https://www.oreilly.com/library/view/javascript-the-good/9780596517748/&quot; class=&quot;link link-external&quot;&gt;Douglas Crockford's book &lt;em&gt;JavaScript: The Good Parts&lt;/em&gt;&lt;/a&gt;.
Chapter 4, &amp;quot;Functions,&amp;quot; has more details,
and also describes two other invocation patterns in JavaScript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the constructor invocation pattern&lt;/li&gt;
&lt;li&gt;the apply invocation pattern.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lastly,
see also my theoretical musings about
&lt;a href=&quot;/blog/illegal-invocations-in-ts/&quot; class=&quot;link&quot;&gt;preventing &amp;quot;illegal invocation&amp;quot; errors in TypeScript&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/dynamic-tag-names-in-pug/</id><title>Dynamic tag names in Pug</title><link href="https://mtsknn.fi/blog/dynamic-tag-names-in-pug/" /><published>2021-01-22T12:00:00+03:00</published><updated>2021-08-27T12:00:00+03:00</updated><category term="Pug"></category><content type="html">&lt;p&gt;Use string interpolation at the beginning of a line,
e.g. &lt;code&gt;#{myVariable}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-pug bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token code&quot;&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'article'&lt;/span&gt;&lt;/span&gt;

#{tag}
#{tag}&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;foo
#{tag}(class&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&quot;foo&quot;)
#{tag}&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;foo(class&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&quot;bar&quot;)
#{tag}(class&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&quot;foo&quot;)&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bar

&lt;span class=&quot;token comment&quot;&gt;// Output:&lt;/span&gt;
&lt;span class=&quot;token markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token 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;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;foo&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;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;foo&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;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;foo bar&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;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;foo bar&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;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Works even inside &lt;a href=&quot;https://pugjs.org/language/interpolation.html#tag-interpolation&quot; class=&quot;link link-external&quot;&gt;tag interpolation&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-pug bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token code&quot;&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'em'&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token plain-text&quot;&gt;Bacon #[#{tag}.foo ipsum]!&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Output:&lt;/span&gt;
&lt;span class=&quot;token markup&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Bacon &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;em&lt;/span&gt; &lt;span class=&quot;token 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;foo&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;ipsum&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;em&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dynamic tag names allow you to use fancy, probably invalid tag names.
Like these:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-pug bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;#{':foo'} bar
#{'^'} baz

&lt;span class=&quot;token comment&quot;&gt;// Output:&lt;/span&gt;
&lt;span class=&quot;token markup&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;:foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;bar&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;:foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token markup&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;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;baz&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;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Compare with:&lt;/span&gt;

:foo bar
&lt;span class=&quot;token comment&quot;&gt;// Error: unknown filter &quot;:foo&quot;&lt;/span&gt;

^ baz
&lt;span class=&quot;token comment&quot;&gt;// Error: unexpected text &quot;^ baz&quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not sure why you would want that though!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pugjs.org/language/interpolation.html&quot; class=&quot;link link-external&quot;&gt;Read more about interpolations in Pug&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/mnemonic-for-array-shift-vs-array-unshift-in-javascript/</id><title>Mnemonic for `array.shift()` vs `array.unshift()` in JavaScript</title><link href="https://mtsknn.fi/blog/mnemonic-for-array-shift-vs-array-unshift-in-javascript/" /><published>2021-01-21T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mnemonics"></category><content type="html">&lt;p&gt;&lt;code&gt;shift()&lt;/code&gt; removes the first array item,
and &lt;code&gt;unshift()&lt;/code&gt; prepends items to the array.
But how to remember which is which?&lt;/p&gt;
&lt;p&gt;First, you need to remember &lt;code&gt;pop()&lt;/code&gt; vs &lt;code&gt;push()&lt;/code&gt;.
If you don't, try these mnemonics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pop()&lt;/code&gt; removes the last array item
by popping it like a bottle cap.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;push()&lt;/code&gt; appends items to the array
by... eh, pushing stuff to it?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think they are quite intuitive.&lt;/p&gt;
&lt;p&gt;All right,
now the mnemonic for &lt;code&gt;shift()&lt;/code&gt; vs &lt;code&gt;unshift()&lt;/code&gt;
(and incidentally also for &lt;code&gt;pop()&lt;/code&gt; vs &lt;code&gt;push()&lt;/code&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The method with the &lt;strong&gt;shorter&lt;/strong&gt; name &lt;strong&gt;removes&lt;/strong&gt; an item.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, &lt;code&gt;pop()&lt;/code&gt; and &lt;code&gt;push()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pop()&lt;/code&gt; has a &lt;strong&gt;shorter&lt;/strong&gt; name than &lt;code&gt;push()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pop()&lt;/code&gt; &lt;strong&gt;removes&lt;/strong&gt; the last array item.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;push()&lt;/code&gt; appends items to the array.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Similarly, &lt;code&gt;shift()&lt;/code&gt; vs &lt;code&gt;unshift()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;shift()&lt;/code&gt; has a &lt;strong&gt;shorter&lt;/strong&gt; name than &lt;code&gt;unshift()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shift()&lt;/code&gt; &lt;strong&gt;removes&lt;/strong&gt; the first array item.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unshift()&lt;/code&gt; prepends items to the array.&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/using-non-default-locales-with-tolocalestring-in-nodejs/</id><title>Using non-default locales with `toLocaleString()` in Node.js</title><link href="https://mtsknn.fi/blog/using-non-default-locales-with-tolocalestring-in-nodejs/" /><published>2021-01-15T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Node.js"></category><content type="html">&lt;p&gt;With Node.js 13+,
it should just work.
With earlier Node.js versions,
you need to install and use the &lt;code&gt;full-icu&lt;/code&gt; package.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using Node.js version 12 or earlier,
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Date.prototype.toLocaleString()&lt;/code&gt;&lt;/a&gt;
and
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Number.prototype.toLocaleString()&lt;/code&gt;&lt;/a&gt;
don't always produce correct results,
at least with non-English (or non-default) locales.
For example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 string&quot;&gt;'2021-11-22'&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;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;'en'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Actual/expected: 11/22/2021, 2:00:00 AM (🆗)&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;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;'fi'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Actual:   2021-11-22 2:00:00 (❗)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Expected: 22.11.2021 klo 2.00.00&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; number &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1234.56&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;number&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;'en'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'currency'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;currency&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'USD'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Actual/expected: $1,234.56 (🆗)&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;number&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;'fi'&lt;/span&gt;&lt;span class=&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;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'currency'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;currency&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'USD'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Actual:   US$ 1,234.56 (❗)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Expected: 1 234,56 $&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-solution&quot;&gt;The solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The results depend on the ICU data (= localization data) used by Node.js.
From &lt;a href=&quot;http://site.icu-project.org/&quot; class=&quot;link link-external&quot;&gt;site.icu-project.org&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ICU is a mature, widely used set of [...] libraries
providing Unicode and Globalization support for software applications.
ICU is widely portable
and gives applications the same results on all platforms [...].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;nodejs-13&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#nodejs-13&quot;&gt;Node.js 13+&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Starting from version 13.0.0,
Node.js comes with full ICU support by default,
so &lt;code&gt;toLocaleString()&lt;/code&gt; should produce correct results.&lt;/p&gt;
&lt;p&gt;From
&lt;a href=&quot;https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V13.md#2019-10-22-version-1300-current-bethgriggs&quot; class=&quot;link link-external&quot;&gt;version 13.0.0 changelog&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Node.js releases are now built with default full-icu support.
This means that all locales supported by ICU are now included
and Intl-related APIs may return different values than before
(Richard Lau)
&lt;a href=&quot;https://github.com/nodejs/node/pull/29887&quot; class=&quot;link link-external&quot;&gt;#29887&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nodejs/node/issues/19214&quot; class=&quot;link link-external&quot;&gt;Issue #19214&lt;/a&gt;
has also relevant discussion about this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;
version 13 is not an LTS (long-time support) version.
Even-numbered versions – 14, 16, 18 and so on –
are LTS versions and thus a better choice.
See &lt;a href=&quot;https://nodejs.org/en/about/releases/&quot; class=&quot;link link-external&quot;&gt;Node.js Releases&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;nodejs-12-and-earlier&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#nodejs-12-and-earlier&quot;&gt;Node.js 12 and earlier&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You need to install and enable full ICU data manually:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;npm install full-icu cross-env&lt;/code&gt;
to install the following packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/full-icu&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;full-icu&lt;/code&gt;&lt;/a&gt;:
the full ICU data&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/cross-env&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;cross-env&lt;/code&gt;&lt;/a&gt;:
needed by Windows users to set the environment variable in the next step.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update the scripts section of &lt;code&gt;package.json&lt;/code&gt;
to set the environment variable &lt;code&gt;NODE_ICU_DATA&lt;/code&gt;.
For example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-json bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&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 comment&quot;&gt;// Before&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;react-scripts start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react-scripts test&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// After&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;react-scripts start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cross-env NODE_ICU_DATA=node_modules/full-icu react-scripts test&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now when you run &lt;code&gt;npm test&lt;/code&gt;,
Node.js will load the full ICU data from &lt;code&gt;node_modules/full-icu&lt;/code&gt;,
and &lt;code&gt;toLocaleString()&lt;/code&gt; should produce correct results.&lt;/p&gt;
&lt;p&gt;In the example above,
you could also modify the &lt;code&gt;start&lt;/code&gt; script,
but it might be unnecessary;
depends on what the script does.
In this case the script opens a browser,
so modifying the script would be unnecessary.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The same info can be found in
&lt;a href=&quot;https://stackoverflow.com/a/56624712/1079869&quot; class=&quot;link link-external&quot;&gt;my Stack Overflow answer&lt;/a&gt;.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/my-new-microphone-rode-procaster/</id><title>My new microphone: RØDE Procaster</title><link href="https://mtsknn.fi/blog/my-new-microphone-rode-procaster/" /><published>2021-01-15T12:00:00+03:00</published><updated>2021-08-22T12:00:00+03:00</updated><category term="Battlestation"></category><content type="html">&lt;p&gt;Much better than a Jabra headset,
but also much pricier.
Why a dynamic XLR microphone
instead of a condenser USB microphone?
Read on to find out.&lt;/p&gt;
&lt;h2 id=&quot;huge-upgrade-from-a-jabra-headset&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#huge-upgrade-from-a-jabra-headset&quot;&gt;Huge upgrade from a Jabra headset&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have previously used a &lt;a href=&quot;https://www.jabra.com/business/office-headsets/jabra-evolve/jabra-evolve-65&quot; class=&quot;link link-external&quot;&gt;Jabra Evolve 65 headset&lt;/a&gt;.
My new &lt;a href=&quot;https://www.rode.com/microphones/procaster&quot; class=&quot;link link-external&quot;&gt;RØDE Procaster microphone&lt;/a&gt;
has so much better audio quality.&lt;/p&gt;
&lt;p&gt;I always thought that the Jabra has quite good audio quality –
and it kind of has; everything is relative.&lt;/p&gt;
&lt;p&gt;But then I compared my voice recorded with the Jabra
to &lt;a href=&quot;https://hanki.dev/&quot; class=&quot;link link-external&quot;&gt;my brother's&lt;/a&gt; voice recorded with a decent condenser microphone.
The difference in audio quality was &lt;em&gt;immense&lt;/em&gt;.
No way I'm going back to the Jabra
(unless I need portability).&lt;/p&gt;
&lt;p&gt;I have worked mostly remotely for the past few years
and plan to continue working remotely,
so having high quality audio equipment benefits my colleagues as well.&lt;/p&gt;
&lt;p&gt;Another reason to buy a decent microphone was that
my brother and I were planning to start a podcast.
(Nowadays our &lt;a href=&quot;https://koodikrapula.fi/&quot; class=&quot;link link-external&quot;&gt;Finnish podcast &lt;em&gt;Koodikrapula&lt;/em&gt;&lt;/a&gt; is up and running.)&lt;/p&gt;
&lt;p&gt;And finally,
&lt;a href=&quot;https://tips.ariyh.com/p/good-sound-quality-smarter&quot; class=&quot;link link-external&quot;&gt;high-quality audio makes you sound smarter&lt;/a&gt;!
(The linked article was published a few months after I had already bought the microphone,
so it didn't affect my purchasing decision.
Cool nonetheless. 🤙)&lt;/p&gt;
&lt;h2 id=&quot;what-did-it-cost&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#what-did-it-cost&quot;&gt;What did it cost?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Everything.&lt;/em&gt; :thanos:&lt;/p&gt;
&lt;p&gt;No but seriously,
these are the prices I paid in Finland in January 2021:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.rode.com/microphones/procaster&quot; class=&quot;link link-external&quot;&gt;RØDE Procaster (microphone)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;179€&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://focusrite.com/en/audio-interface/scarlett/scarlett-solo&quot; class=&quot;link link-external&quot;&gt;Focusrite Scarlett Solo 3rd Gen (USB audio interface)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;110€&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.rode.com/accessories/stands/psa1&quot; class=&quot;link link-external&quot;&gt;RØDE PSA1 (studio arm)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;70€&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.rode.com/accessories/psm1&quot; class=&quot;link link-external&quot;&gt;RØDE PSM1 (shock mount)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;40€&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cordial-cables.com/en/products/cim-fm&quot; class=&quot;link link-external&quot;&gt;Cordial Silver Line (2.5m XLR–XLR cable)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;21€&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.rode.com/accessories/ws2&quot; class=&quot;link link-external&quot;&gt;RØDE WS2 (pop filter / wind shield)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;16€&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Total price: 436€ 🙈&lt;/p&gt;
&lt;p&gt;In comparison,
the Jabra Evolve 65 headset costs about 130€.&lt;/p&gt;
&lt;p&gt;I got the RØDE PSA1 studio arm on sale (70€);
normally it costs ~90€.&lt;/p&gt;
&lt;h2 id=&quot;different-kinds-of-microphones&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#different-kinds-of-microphones&quot;&gt;Different kinds of microphones&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When deciding what microphone to buy,
I watched some videos.&lt;/p&gt;
&lt;h3 id=&quot;xlr-vs-usb&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#xlr-vs-usb&quot;&gt;XLR vs USB&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;From
&lt;a href=&quot;https://www.youtube.com/watch?v=lQOU2oQlH00&quot; class=&quot;link link-external&quot;&gt;Podcastage's video &lt;em&gt;XLR vs USB Microphones, Which Should You Buy?&lt;/em&gt;&lt;/a&gt;,
I learned that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;USB microphones are easier to use.&lt;/li&gt;
&lt;li&gt;XLR microphones offer better audio quality and more choices,
but they require an USB audio interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thus, I opted for an XLR microphone.
There's no such thing as overkill
when it comes to audio stuff,
right?&lt;/p&gt;
&lt;h3 id=&quot;dynamic-vs-condenser&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#dynamic-vs-condenser&quot;&gt;Dynamic vs condenser&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;From
&lt;a href=&quot;https://www.youtube.com/watch?v=Y01N_L1VA4I&quot; class=&quot;link link-external&quot;&gt;Podcastage's video &lt;em&gt;Dynamic vs Condenser Microphones, What's the Difference?&lt;/em&gt;&lt;/a&gt;,
I learned that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Condenser microphones are more sensitive
so they pick up more background noises,
like the sound of the keyboard, air conditioner etc.&lt;/li&gt;
&lt;li&gt;Dynamic microphones are better at suppressing background noises
at the cost of reduced audio quality.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my case,
I'm sure no one (including me) would notice the difference in audio quality
between a dynamic and a condenser microphone.
But background noises are always annoying,
so I opted for a dynamic microphone.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/locality-of-behavior-and-co-location/</id><title>Locality of Behavior / Co-location</title><link href="https://mtsknn.fi/blog/locality-of-behavior-and-co-location/" /><published>2021-01-15T12:00:00+03:00</published><updated>2021-10-23T12:00:00+03:00</updated><category term="Clean code"></category><category term="CSS"></category><category term="JavaScript"></category><content type="html">&lt;p&gt;These two similar principles state that
the behavior of code should be obvious on inspection
and that code should be located where it's relevant.&lt;/p&gt;
&lt;h2 id=&quot;locality-of-behavior&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#locality-of-behavior&quot;&gt;Locality of Behavior&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://htmx.org/essays/locality-of-behaviour/&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Locality of Behavior&lt;/em&gt; principle&lt;/a&gt;
states that the behavior of code should be obvious on inspection.
Or more formally:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The behavior of a unit of code
should be as obvious as possible
by looking only at that unit of code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An example from the linked article:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider two different implementations of an AJAX request in HTML,
the first in &lt;a href=&quot;https://htmx.org/&quot; class=&quot;link link-external&quot;&gt;htmx&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hx-get&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;/clicked&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;Click 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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the second in jQuery:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'#d1'&lt;/span&gt;&lt;span class=&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;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'click'&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 function&quot;&gt;ajax&lt;/span&gt;&lt;span class=&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;/* AJAX options... */&lt;/span&gt;
  &lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;d1&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;Click 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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the former,
the behavior of the &lt;code&gt;button&lt;/code&gt; element is obvious on inspection,
satisfying the Locality of Behavior principle.&lt;/p&gt;
&lt;p&gt;In the latter,
the behavior of the &lt;code&gt;button&lt;/code&gt; element is spread out amongst multiple files.
It is difficult to know exactly what the button does
without a total knowledge of the code base.
This &amp;quot;spooky action at a distance&amp;quot; is a source of maintenance issues
and stands in the way of developers understanding of the code base.&lt;/p&gt;
&lt;p&gt;The htmx example demonstrates good Locality of Behavior,
while the jQuery example has poor Locality of Behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://htmx.org/essays/locality-of-behaviour/&quot; class=&quot;link link-external&quot;&gt;Read more about the Locality of Behavior principle&lt;/a&gt;
from htmx's docs.&lt;/p&gt;
&lt;h2 id=&quot;co-location&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#co-location&quot;&gt;Co-location&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://kentcdodds.com/blog/colocation&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Co-location&lt;/em&gt; principle&lt;/a&gt;
states that code should be located where it's relevant.
Or more formally:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Place code as close to where it's relevant as possible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And in other words:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Things that change together should be located as close as reasonable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some examples from the linked article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code comments are usually &amp;quot;co-located&amp;quot; with the code they are explaining
instead of being somewhere else entirely,
e.g. in a separate &lt;code&gt;docs/&lt;/code&gt; folder.
(This is a contrived example,
but demonstrates the importance of the Co-location principle well.)&lt;/li&gt;
&lt;li&gt;React/Vue/etc. components often contain
both the view logic and the view template.&lt;/li&gt;
&lt;li&gt;If unit test files are located next to the source files,
it's very easy to locate the unit tests for a source file.
For example,
&lt;code&gt;Button.js&lt;/code&gt; and &lt;code&gt;Button.test.js&lt;/code&gt; in the same folder are co-located,
but &lt;code&gt;src/.../Button.js&lt;/code&gt; and &lt;code&gt;tests/.../Button.test.js&lt;/code&gt; are not.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://kentcdodds.com/blog/colocation&quot; class=&quot;link link-external&quot;&gt;Read more about the Co-location principle&lt;/a&gt;
from Kent C. Dodds's blog.&lt;/p&gt;
&lt;h2 id=&quot;example-tailwind&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-tailwind&quot;&gt;Example: Tailwind 🥰&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Locality of Behavior and Co-location principles partly explain
why I feel productive and happy when using &lt;a href=&quot;https://tailwindcss.com/&quot; class=&quot;link link-external&quot;&gt;Tailwind&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example,
when using Tailwind with React,
a single component file can contain everything relevant about the component&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTML structure (JSX)&lt;/li&gt;
&lt;li&gt;event listeners (&lt;code&gt;onClick&lt;/code&gt; etc.)&lt;/li&gt;
&lt;li&gt;logic and state (hooks etc.)&lt;/li&gt;
&lt;li&gt;styles (Tailwind classes amongst the JSX).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With Tailwind,
I can stay in the component's JS file.
Without Tailwind,
I would need to jump between the component's JS and CSS files.&lt;/p&gt;
&lt;p&gt;To be fair,
CSS-in-JS could offer similar benefits as Tailwind.&lt;/p&gt;
&lt;p&gt;CSS modules would be worse (separate CSS file),
but at least they would be imported from components' JS files,
so it would be easy to locate a component's styles.&lt;/p&gt;
&lt;p&gt;Global CSS files would be the worst option
from the viewpoint of the Locality of Behavior and Co-location principles.&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;I have heard that Vue provides a similarly pleasant experience
with its single-file components. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/calculating-week-numbers-in-js-is-surprisingly-complex/</id><title>Calculating week numbers in JS is surprisingly complex</title><link href="https://mtsknn.fi/blog/calculating-week-numbers-in-js-is-surprisingly-complex/" /><published>2021-01-15T12:00:00+03:00</published><updated>2021-01-15T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;JavaScript doesn't provide a native way
to get the week number of a date.
Just use a library instead.&lt;/p&gt;
&lt;p&gt;It might be complex because
&lt;a href=&quot;https://en.wikipedia.org/wiki/Week#Week_numbering&quot; class=&quot;link link-external&quot;&gt;week numbering itself is complicated&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my case,
I ended up using the
&lt;a href=&quot;https://date-fns.org/v2.23.0/docs/getWeek&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;getWeek()&lt;/code&gt; function from date-fns&lt;/a&gt;.
This piece from
&lt;a href=&quot;https://github.com/date-fns/date-fns/blob/v2.23.0/src/getWeek/index.ts&quot; class=&quot;link link-external&quot;&gt;its implementation on GitHub&lt;/a&gt;
is amusing:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Round the number of days to the nearest integer&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// because the number of milliseconds in a week is not constant&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// (e.g. it's different in the week of the daylight saving time clock shift)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;diff &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MILLISECONDS_IN_WEEK&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm glad I haven't had to deal with date stuff much in the past.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-do-overlapping-matches-with-regular-expressions/</id><title>How to do overlapping matches with regular expressions</title><link href="https://mtsknn.fi/blog/how-to-do-overlapping-matches-with-regular-expressions/" /><published>2021-01-13T12:00:00+03:00</published><updated>2022-12-07T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Regular expressions"></category><content type="html">&lt;p&gt;E.g. how to capture overlapping pairs of letters from the string &lt;code&gt;'abcde'&lt;/code&gt;,
i.e. &lt;code&gt;'ab'&lt;/code&gt;, &lt;code&gt;'bc'&lt;/code&gt;, &lt;code&gt;'cd'&lt;/code&gt; and &lt;code&gt;'de'&lt;/code&gt;.
Spoiler: with lookahead and lookbehind assertions.&lt;/p&gt;
&lt;h2 id=&quot;consuming-characters-vs-looking-ahead-behind&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#consuming-characters-vs-looking-ahead-behind&quot;&gt;Consuming characters vs looking ahead/behind&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We could try matching two letters at a time, like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[a-z][a-z]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['ab', 'cd']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it doesn't work.
Why not?&lt;/p&gt;
&lt;p&gt;Turns out that when the regular expression matches the first two letters
(&lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;),
it &lt;em&gt;consumes&lt;/em&gt; them,
meaning that
the next match will be done against the rest of the input string,
i.e. &lt;code&gt;'cde'&lt;/code&gt;.
That's why the above regular expression doesn't capture overlapping pairs of letters.&lt;/p&gt;
&lt;p&gt;This is what &lt;strong&gt;lookahead and lookbehind assertions&lt;/strong&gt; are for:
they &lt;em&gt;look ahead or behind to assert (check)&lt;/em&gt;
that the input contains some characters,
but they don't &lt;em&gt;consume&lt;/em&gt; those characters.&lt;/p&gt;
&lt;p&gt;We have two options:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lookahead &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;(?=[a-z][a-z])&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lookbehind &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;(?&amp;lt;=[a-z][a-z])&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first regular expression above has a lookahead assertion.
When it's used to loop through the input string,
it &lt;em&gt;asserts&lt;/em&gt; that the current position is followed by two letters.
It doesn't &lt;em&gt;consume&lt;/em&gt; them because they are inside the lookahead assertion.
In fact,
the regular expression doesn't consume &lt;em&gt;any&lt;/em&gt; characters
because all matchable characters are inside the lookahead assertion.&lt;/p&gt;
&lt;p&gt;The second regular expression above has a lookbehind assertion.
It works similarly,
but it asserts that the current character is &lt;em&gt;preceded&lt;/em&gt; by two letters.&lt;/p&gt;
&lt;p&gt;Here's a table of the lookahead/lookbehind assertion results
using the two regular expressions above for the string &lt;code&gt;'abcde'&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Index&lt;/th&gt;
&lt;th&gt;Position &lt;span class=&quot;whitespace-no-wrap&quot;&gt;(&lt;code&gt;|&lt;/code&gt;)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;Match&lt;/th&gt;
&lt;th&gt;Look­ahead&lt;/th&gt;
&lt;th&gt;Look­behind&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;|abcde&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a|bcde&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ab|cde&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abc|de&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;de&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abcd|e&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abcde|&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;de&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;How does this help us?
It does if we use capturing groups.&lt;/p&gt;
&lt;h2 id=&quot;capturing-groups-inside-lookahead-lookbehind-assertions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#capturing-groups-inside-lookahead-lookbehind-assertions&quot;&gt;Capturing groups inside lookahead/lookbehind assertions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We now know how to loop through the input string
and look ahead/behind to find all (overlapping) pairs of letters.
We can &lt;em&gt;capture&lt;/em&gt; the pairs
by using capturing groups inside the lookahead/lookbehind assertions:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lookahead &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;(?=[a-z][a-z])&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lookbehind &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;(?&amp;lt;=[a-z][a-z])&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lookahead &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;(?=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//                    ^          ^&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lookbehind &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;(?&amp;lt;=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//                      ^          ^&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One caveat, though:
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;String.prototype.match()&lt;/code&gt;&lt;/a&gt;
ignores capturing groups when using the global flag (&lt;code&gt;g&lt;/code&gt;).
So these don't work:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['', '', '', '']&lt;/span&gt;

&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; ['', '', '', '']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They don't work because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;all matchable characters are inside the lookahead/lookbehind assertions,
so the regular expressions capture nothing&lt;/li&gt;
&lt;li&gt;&lt;code&gt;match()&lt;/code&gt; ignores capturing groups when using the global flag (&lt;code&gt;g&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Luckily for us,
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;String.prototype.matchAll()&lt;/code&gt;&lt;/a&gt;
does not ignore capturing groups:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; RegExpStringIterator {}&lt;/span&gt;

&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; RegExpStringIterator {}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But oh, &lt;code&gt;matchAll()&lt;/code&gt; returns an iterator.
Let's convert the iterators to arrays:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&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 comment&quot;&gt;//=&gt; [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;ab&quot;, index: 0, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;bc&quot;, index: 1, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;cd&quot;, index: 2, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;de&quot;, index: 3, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;

Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&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 comment&quot;&gt;//=&gt; [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;ab&quot;, index: 2, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;bc&quot;, index: 3, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;cd&quot;, index: 4, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//     [&quot;&quot;, &quot;de&quot;, index: 5, input: &quot;abcde&quot;, groups: undefined],&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   ]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that each array item is an array with
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#Additional_properties&quot; class=&quot;link link-external&quot;&gt;additional properties&lt;/a&gt;.
The first items are the matches –
they are empty strings
because all matchable characters are inside the lookahead/lookbehind assertions.
The second items are the matches from the capturing groups.&lt;/p&gt;
&lt;p&gt;Because we are using
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Array.from()&lt;/code&gt;&lt;/a&gt;,
we can easily get only the second array items:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&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 parameter&quot;&gt;match&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; match&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 comment&quot;&gt;//=&gt; ['ab', 'bc', 'cd', 'de']&lt;/span&gt;

Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'abcde'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?&amp;lt;=([a-z][a-z]))&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&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 parameter&quot;&gt;match&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; match&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 comment&quot;&gt;//=&gt; ['ab', 'bc', 'cd', 'de']&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that's how we can do overlapping matches with regular expressions.
Or that's the gist of it;
depending on your needs,
you can also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use negative lookahead/lookbehind assertions&lt;/li&gt;
&lt;li&gt;put stuff outside the lookahead/lookbehind assertion.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;practical-applications&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#practical-applications&quot;&gt;Practical applications&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using overlapping regex matches is one way to
&lt;a href=&quot;https://mtsknn.fi/blog/converting-a-path-into-cumulative-segments-in-javascript/&quot; class=&quot;link&quot;&gt;convert a directory path or URL pathname into cumulative segments&lt;/a&gt;;
e.g. converting
&lt;code&gt;'/foo/bar/baz/'&lt;/code&gt;
into an array of
&lt;code&gt;'/'&lt;/code&gt;, &lt;code&gt;'/foo/'&lt;/code&gt;, &lt;code&gt;'/foo/bar/'&lt;/code&gt; and &lt;code&gt;'/foo/bar/baz/'&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Anthony Labarre emailed me about another interesting use case:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I used this as an exercise in bash scripting for Chinese students, where I had them extract Chinese &amp;quot;proverbs&amp;quot; from books.
A faster solution than searching the book for each proverb in a list consists in generating all possibly overlapping subsequences of 4, 5, … characters from the book, and then using &lt;code&gt;comm&lt;/code&gt; to identify which subsequences match known proverbs from our list.
On my machine, this brought the running time from about 15 seconds to about 1 second.&lt;/p&gt;
&lt;p&gt;For completeness, &lt;a href=&quot;https://unix.stackexchange.com/a/725518/&quot; class=&quot;link link-external&quot;&gt;here's how I did it in bash&lt;/a&gt; [...].
(Except &lt;code&gt;\w&lt;/code&gt; does not work for Chinese characters, you need to substitute it with &lt;code&gt;\p{Han}&lt;/code&gt; and add the &lt;code&gt;-u&lt;/code&gt; flag to &lt;code&gt;pcregrep&lt;/code&gt;.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Have you found overlapping regex matches useful in other scenarios?
Let me know! (Email on the front page.)&lt;/p&gt;
&lt;h2 id=&quot;browser-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#browser-support&quot;&gt;Browser support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As of March 2022:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/sr_js-regexp-lookahead&quot; class=&quot;link link-external&quot;&gt;Lookahead assertions are supported by all browsers&lt;/a&gt;
because they &amp;quot;are part of JavaScript's original regular expression support.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/js-regexp-lookbehind&quot; class=&quot;link link-external&quot;&gt;Lookbehind assertions are supported by all modern browsers except Safari and iOS Safari.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/mdn-javascript_builtins_string_matchall&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;String.prototype.matchAll()&lt;/code&gt; is supported by all modern browsers.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/a/33903830/1079869&quot; class=&quot;link link-external&quot;&gt;Wiktor Stribiżew's answer to &lt;em&gt;How can I match overlapping strings with regex?&lt;/em&gt; on Stack Overflow&lt;/a&gt;
shows how to do overlapping matches by using
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;RegExp.prototype.exec()&lt;/code&gt;&lt;/a&gt;
and modifying the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex&quot; class=&quot;link link-external&quot;&gt;regular expression instance's &lt;code&gt;lastIndex&lt;/code&gt; property&lt;/a&gt;.
This is useful if you can't use &lt;code&gt;matchAll()&lt;/code&gt;,
which isn't supported by Internet Explorer.&lt;/p&gt;
&lt;p&gt;Wiktor's answer also shows the solution that I have presented here;
I actually learned it from Wiktor's answer (thanks!).
This blog post is mainly me teaching myself the topic
by teaching it to you.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/fn-apply-vs-fn-call-in-javascript-better-alternative/</id><title>`fn.apply()` vs `fn.call()` in JavaScript + better alternative</title><link href="https://mtsknn.fi/blog/fn-apply-vs-fn-call-in-javascript-better-alternative/" /><published>2021-01-11T12:00:00+03:00</published><updated>2021-10-26T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mnemonics"></category><content type="html">&lt;p&gt;Mnemonic:
&amp;quot;a&amp;quot; (&lt;code&gt;apply()&lt;/code&gt;) for an array,
&amp;quot;c&amp;quot; (&lt;code&gt;call()&lt;/code&gt;) for commas.
But &lt;code&gt;Reflect.apply()&lt;/code&gt; is better.&lt;/p&gt;
&lt;h2 id=&quot;fnapply-vs-fncall&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#fnapply-vs-fncall&quot;&gt;&lt;code&gt;fn.apply()&lt;/code&gt; vs &lt;code&gt;fn.call()&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;apply()&lt;/code&gt; method&lt;/a&gt;
takes arguments as an array,
and the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;call()&lt;/code&gt; method&lt;/a&gt;
takes multiple arguments:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&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; thisArg &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 keyword&quot;&gt;const&lt;/span&gt; args &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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thisArg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thisArg&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thisArg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thisArg&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mnemonic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a&lt;/strong&gt; (&lt;code&gt;apply()&lt;/code&gt;) for an &lt;strong&gt;a&lt;/strong&gt;rray&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;c&lt;/strong&gt; (&lt;code&gt;call()&lt;/code&gt;) for &lt;strong&gt;c&lt;/strong&gt;ommas.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Source for the mnemonic:
&lt;a href=&quot;https://stackoverflow.com/q/1986896/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;What is the difference between call and apply?&lt;/em&gt; on Stack Overflow&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-better-alternative&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-better-alternative&quot;&gt;The better alternative&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/apply&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Reflect.apply()&lt;/code&gt;&lt;/a&gt;
is better.
Like &lt;code&gt;fn.apply()&lt;/code&gt;,
it takes arguments as an array:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&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; thisArg &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 keyword&quot;&gt;const&lt;/span&gt; args &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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;Reflect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; thisArg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Reflect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; thisArg&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's &amp;quot;arguably less verbose and easier to understand&amp;quot; than &lt;code&gt;fn.apply()&lt;/code&gt;.
&amp;quot;In addition,
when you accept arbitrary methods,
it's not safe to assume &lt;code&gt;.apply()&lt;/code&gt; exists or is not overridden.&amp;quot;&lt;/p&gt;
&lt;p&gt;Source:
&lt;a href=&quot;https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v25.0.1/docs/rules/prefer-reflect-apply.md&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Prefer &lt;code&gt;Reflect.apply()&lt;/code&gt; over &lt;code&gt;Function#apply()&lt;/code&gt;&lt;/em&gt; ESLint rule&lt;/a&gt;
from
&lt;a href=&quot;https://github.com/sindresorhus/eslint-plugin-unicorn&quot; class=&quot;link link-external&quot;&gt;eslint-plugin-unicorn&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;a-note-about-verbosity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#a-note-about-verbosity&quot;&gt;A note about verbosity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is not verbose:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thisArg&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it's not safe either as stated above.&lt;/p&gt;
&lt;p&gt;This is safe but also verbose:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; thisArg&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it's easy to see
why &lt;code&gt;Reflect.apply()&lt;/code&gt; is &amp;quot;arguably less verbose and easier to understand&amp;quot;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Reflect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; thisArg&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBGADGgNCAZhBAzsgNqgB2AhmIkiAHQBWR2AxgPZkAu8XyIA7hDJQ2-OjjZsABAF4pAHQFCR-AOQEpEtovllBw0XQBGFAF6yFSg2o0nTOsrpwBXMi04QOmsgAo6-igAnAHMCAEopYF0pKSDQ8TZAgFEKFgALHx84iJkAPil2MgI2BDpYNmCskMwpVSRVGs40iAJiOIBdMLDdAF9dXUKCTik2IwYLKLIYrSRLUYZ1TUlFTGipE0DZxXnFjZXegY4h2JCNOWJVLQbajevVO1V2-rcjkvgyip9VKAhA+HcChRYLBVN0yDhfP46HFws9Bm8PpVVPInGRoQAHdGwACePjCoNRGKxuPmNRhYMORQR5SRKPBaJYQNgeIJ9LojOBPlJUih5Lhr1KNK+dIASvAcAh3EScSywWKJf9ONLcRCaty+WQQNgCPBJR4jnwAEwAZiQhoAHCAeu0ekA&quot; class=&quot;link link-external&quot;&gt;Test the code on flems.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://old.reddit.com/r/javascript/comments/klkj1e/60_useful_eslint_rules/&quot; class=&quot;link link-external&quot;&gt;Recent (December 2020) Reddit discussion about eslint-plugin-unicorn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/when-to-use-the-xmlns-and-version-svg-attributes/</id><title>When to use the `xmlns` and `version` SVG attributes</title><link href="https://mtsknn.fi/blog/when-to-use-the-xmlns-and-version-svg-attributes/" /><published>2021-01-08T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="SVG"></category><content type="html">&lt;p&gt;The &lt;code&gt;xmlns&lt;/code&gt; attribute is required for SVG files
but optional for inlined SVGs.
The &lt;code&gt;version&lt;/code&gt; attribute is always optional.&lt;/p&gt;
&lt;h2 id=&quot;the-xmlns-and-xmlnsxlink-attributes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-xmlns-and-xmlnsxlink-attributes&quot;&gt;The &lt;code&gt;xmlns&lt;/code&gt; and &lt;code&gt;xmlns:xlink&lt;/code&gt; attributes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;xmlns&lt;/code&gt; and &lt;code&gt;xmlns:xlink&lt;/code&gt; attributes are
&lt;strong&gt;optional for inlined SVGs in HTML&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;xmlns&lt;/code&gt; attribute is
&lt;strong&gt;required for SVG files&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;xmlns&lt;/code&gt; attribute is
&lt;strong&gt;required for SVGs in CSS&lt;/strong&gt;, e.g.:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;'data:image/svg+xml;utf8,&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;...&amp;lt;/svg&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;xmlns:xlink&lt;/code&gt; attribute is required
for SVG files that contain &lt;code&gt;xlink:&lt;/code&gt; attributes.
Similarly for SVGs in CSS.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-version-attribute&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-version-attribute&quot;&gt;The &lt;code&gt;version&lt;/code&gt; attribute&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;version&lt;/code&gt; attribute is ignored and thus &lt;strong&gt;always optional&lt;/strong&gt;.
Plus it's deprecated since SVG 2.&lt;/p&gt;
&lt;h2 id=&quot;source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#source&quot;&gt;Source&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/q/18467982/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Are SVG parameters such as 'xmlns' and 'version' needed?&lt;/em&gt; on Stack Overflow&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/uncontrolled-form-inputs-in-react/</id><title>Uncontrolled form inputs in React</title><link href="https://mtsknn.fi/blog/uncontrolled-form-inputs-in-react/" /><published>2021-01-08T12:00:00+03:00</published><updated>2021-10-16T12:00:00+03:00</updated><category term="JavaScript"></category><category term="React"></category><content type="html">&lt;p&gt;If you need form input values only at the time of form submission,
uncontrolled inputs can be nice to work with.&lt;/p&gt;
&lt;p&gt;From &lt;a href=&quot;https://reactjs.org/docs/uncontrolled-components.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Uncontrolled Components&lt;/em&gt; on React docs&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In most cases,
we recommend using &lt;a href=&quot;https://reactjs.org/docs/forms.html#controlled-components&quot; class=&quot;link link-external&quot;&gt;controlled components&lt;/a&gt;
to implement forms.
In a controlled component,
form data is handled by a React component.
The alternative is uncontrolled components,
where form data is handled by the DOM itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I previously thought that
using uncontrolled inputs in React
is very rare or even a bad practice.&lt;/p&gt;
&lt;p&gt;But then I found this
&lt;a href=&quot;https://twitter.com/JoshWComeau/status/1330302183431147526&quot; class=&quot;link link-external&quot;&gt;tweet by Josh W. Comeau&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🌠 I've been really enjoying using uncontrolled form inputs recently.
Set an initial value with React,
and then collect the values using standard JS when the form is submitted.&lt;/p&gt;
&lt;p&gt;No fussing with state required 🔥&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://codesandbox.io/s/jovial-prosk&quot; class=&quot;link link-external&quot;&gt;CodeSandbox demo&lt;/a&gt;&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;EditUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; user &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saveUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ev&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&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; elementsArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;ev&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elements&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elementsArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; elem&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;elem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;elem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc
    &lt;span class=&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;// Do a `fetch` or whatever with `formData`!&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Has the shape: `{ name: string, email: string }`&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;saveUser&lt;span class=&quot;token punctuation&quot;&gt;}&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 plain-text&quot;&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 plain-text&quot;&gt;
        Name
        &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;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;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;defaultValue&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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 plain-text&quot;&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Save&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;It makes sense to use uncontrolled form inputs
if the input values are needed only at the time of form submission.
I'd imagine the performance must be better as well.&lt;/p&gt;
&lt;p&gt;From the replies on Twitter:
creating a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FormData&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;FormData&lt;/code&gt; object&lt;/a&gt;
simplifies the &lt;code&gt;saveUser&lt;/code&gt; function even more:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-diff-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saveUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  ev&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&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 class=&quot;token deleted-sign deleted language-js&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; elementsArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;ev&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elements&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elementsArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; elem&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 prefix deleted&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;elem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;elem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value
&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc
&lt;span class=&quot;token prefix deleted&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&gt;&lt;span class=&quot;token inserted-sign inserted language-js&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formData &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;FormData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ev&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;token unchanged language-js&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Do a `fetch` or whatever with `formData`!&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that form inputs need to have a &lt;code&gt;name&lt;/code&gt; prop/attribute
or they won't end up in the &lt;code&gt;formData&lt;/code&gt; object (if using &lt;code&gt;new FormData(ev.target)&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Usage of the &lt;code&gt;formData&lt;/code&gt; object:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saveUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ev&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&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; formData &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;FormData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ev&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// `Content-Type` will implicitly be `multipart/form-data`&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&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;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; formData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&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;// or&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pojo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromEntries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;formData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pojo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&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;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; json&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;headers&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-property property&quot;&gt;'Content-Type'&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'POST'&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgAsAXLKEAGhAGMB7NYmBvAHgBMIA3AAgjYF4AOiAwAHUcIB8LAPQdOkkAF8K6bLkQEAVgip0GTYnhkzuJYqLiITWYnADWaNPkgyARlFoBzGQFc0+sQATrRQsGwAtGC0QVgREGiivnbxaBFBMBjUxDKCaHlg-tkQ9NwAohzEAKpwMEEAFMDcvrVB3EoAlNzAedzchQHEJWjccBicMDV19TCcXT0jfdyz+KIZEwwAIjBgGL5QxPUdvUsnffpwxP0xWJsYxBjc-NxoMADu3ABiN3cPM5z4B5BLwwYjHRZ9M7cEzcAAGAGF6IwGBEACoAT1EMFh3De0CgvCwoigEGoEGIUHR3DcMDhWH2Q1EGCCOWisQibHuGFhULAoOohHqAHIZIxLkKKN0oX03LQ2OjENdYr8MBRpdwcMRCHLFUKAAoAeQAyqiJVDOlCoTCYmcoRcrqJaFpaE9uAa3FoYNkXCEsGUGEEIPB6mzblzwUtuPbuDpSs8AFJGg0AOXwl0DaC8EDA6PqjudEaWfOIAuFovgxAlUohS1l8sVsbQaprfUImTYdSs3W4QsRBhRGKxQt1YmJpPuwxkjaF7Wbkb6mu1bF1hpNZprFvyNYwsBZwvhbeo9m4WtpxYF3AyAEdfBW4LwRqfuMnQW8YseHm5uLQwNxtpxUVoUI4CFQslDyE4MmIXwghGeooRYUNvzQI1fDcLByX4YAxgmKYgiUSR1RYKAMBpKBCJbJZk3UYAZyFcDKL6FgEiSK5iExGAhBARgAA9iGEXgBGETAcAEkTOOE9QBI7XYGQANR3W8sJaOp8HEpRoQo+duFkEiyK0+diNImByPVJYyiwDBoFonsGO0pZmMSZITw4riYEs6ABL4NyPKgMT1B8qy-JAbgZL2A4FKgJTgBUoJ8HcoKNJkAzDJkPSTJShy3GSYh6EkI1xhgWRsuIXK0Ey2RQwM8EGLyAAlTJsk2A0AFl8AyNAOwaE4WAqck8OaVosKacTdXjWhCDQGclCSyQ51C2hqF8HAGHwG86nRI0TK9XKGiFABiUdQLycFKBoWgiWgOo8DcYzyBUNQcDwfBqDgXRzv7IxNHSgkFj6Dg4GJDAFWpTwjwAbjyJQztqWBinoBBNAARkQJGAHZlAAXSoEk0HsRHUBAcS8AyLIjCoGDyE0cxLGsPxEnsLwXoumRSeyPwsDYVnGuIfAOwmTxRBW3mdDO9isTwOBqEDUQjAeon1BJnmOQus7KbwGmrBMfxREZ5msG5smVYN5aubZ4hjb52YTNoIXDHwUWqHFjQQClmW5exhWns0KoAiREIwhgNglSwB9WPvBJuAasnlCAA&quot; class=&quot;link link-external&quot;&gt;Demo on flems.io&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/notes-on-tail-call-optimization-the-musical/</id><title>My notes on &quot;Tail Call Optimization: The Musical!&quot;</title><link href="https://mtsknn.fi/blog/notes-on-tail-call-optimization-the-musical/" /><published>2021-01-08T12:00:00+03:00</published><updated>2021-08-26T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;My quick notes on a funny but informative video (11:27)
that explains how tail call optimization (TCO) works.
Bonus: does JS support TCO?
Spoiler: yes but no.&lt;/p&gt;
&lt;h2 id=&quot;the-video&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-video&quot;&gt;The video&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=-PX0BV9hGZY&quot; class=&quot;link link-external&quot;&gt;Watch the video on YouTube&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(Note to self:
embed the video using &lt;a href=&quot;https://github.com/paulirish/lite-youtube-embed&quot; class=&quot;link link-external&quot;&gt;Lite YouTube Embed&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id=&quot;my-notes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#my-notes&quot;&gt;My notes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tail call = a function call at the very end of a function,
i.e. the function call has to be the very last thing that the function does.&lt;/li&gt;
&lt;li&gt;Tail call optimization (TCO) = if the language (and engine) supports TCO,
tail calls are removed from the call stack
because they are kind of unnecessarily there
(because of the tail position).
&lt;ul&gt;
&lt;li&gt;Pro:
You don't get errors saying
&amp;quot;Maximum call stack size exceeded&amp;quot; (Chrome)
or &amp;quot;Too much recursion&amp;quot; (Firefox)
or &amp;quot;Stack overflow&amp;quot; (some other contexts).&lt;/li&gt;
&lt;li&gt;Con:
Stack traces have less information
(because tail calls have been removed from the call stack),
making debugging errors potentially more difficult.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bonus-does-javascript-support-tco&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bonus-does-javascript-support-tco&quot;&gt;Bonus: Does JavaScript support TCO?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not in the video but relevant:
ECMAScript 6 offers TCO,
but TCO &amp;quot;isn't supported by many [JavaScript] engines and that may never change.&amp;quot;
Source:
&lt;a href=&quot;https://2ality.com/2015/06/tail-call-optimization.html&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Tail call optimization in ECMAScript 6&lt;/em&gt; by Dr. Axel Rauschmayer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://kangax.github.io/compat-table/es6/#test-proper_tail_calls_(tail_call_optimisation)&quot; class=&quot;link link-external&quot;&gt;ECMAScript 6 compatibility table&lt;/a&gt;
shows that there indeed are not many browsers/engines that support TCO –
only these (as of Aug 26, 2021):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Safari 14+&lt;/li&gt;
&lt;li&gt;iOS Safari 12+&lt;/li&gt;
&lt;li&gt;WebKit, the browser engine used by Safari and iOS Safari&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Kinoma/kinomajs&quot; class=&quot;link link-external&quot;&gt;Kinoma XS6&lt;/a&gt;,
&amp;quot;a JavaScript runtime optimized for the applications that power IoT devices&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-sort-package-json-automatically/</id><title>How to sort `package.json` automatically</title><link href="https://mtsknn.fi/blog/how-to-sort-package-json-automatically/" /><published>2021-01-06T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;Just run &lt;code&gt;npx sort-package-json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This takes about 4–8 seconds on my machine
because &lt;code&gt;npx&lt;/code&gt; has to first download the &lt;a href=&quot;https://www.npmjs.com/package/sort-package-json&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;sort-package-json&lt;/code&gt; package&lt;/a&gt;.
If that's too slow for you,
install the package globally:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;#  i =   install&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# -g = --global&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i -g sort-package-json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can run just:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;sort-package-json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it will take less than a second.&lt;/p&gt;
&lt;p&gt;You can also install the package locally
and even run it in Git's pre-commit hook (using &lt;a href=&quot;https://www.npmjs.com/package/husky&quot; class=&quot;link link-external&quot;&gt;Husky&lt;/a&gt; or &lt;a href=&quot;https://github.com/Arkweid/lefthook&quot; class=&quot;link link-external&quot;&gt;Lefthook&lt;/a&gt;)
or in your CI pipeline.
More options are mentioned in &lt;a href=&quot;https://www.npmjs.com/package/sort-package-json&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;sort-package-json&lt;/code&gt;'s documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://stackoverflow.com/a/48276232/1079869&quot; class=&quot;link link-external&quot;&gt;My own Stack Overflow answer&lt;/a&gt;&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-force-push-in-git-with-style-and-some-safety/</id><title>How to force push in Git with style (and some safety)</title><link href="https://mtsknn.fi/blog/how-to-force-push-in-git-with-style-and-some-safety/" /><published>2021-01-04T12:00:00+03:00</published><updated>2021-06-11T12:00:00+03:00</updated><category term="Git"></category><content type="html">&lt;p&gt;Never run &lt;code&gt;git push --force&lt;/code&gt;.
Instead run &lt;code&gt;git push --force-with-lease&lt;/code&gt;
or alias it to &lt;code&gt;git please&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;please-be-polite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#please-be-polite&quot;&gt;Please be polite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Never run &lt;code&gt;git push --force&lt;/code&gt;
or you might overwrite commits pushed by others.
Instead run:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push --force-with-lease
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or if using
&lt;a href=&quot;https://github.com/mtsknn/dotfiles/blob/master/.gitconfig&quot; class=&quot;link link-external&quot;&gt;my Git aliases&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; please
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please = force &lt;strong&gt;p&lt;/strong&gt;ush with &lt;strong&gt;lease&lt;/strong&gt;.
So polite!&lt;/p&gt;
&lt;p&gt;(Unfortunately I don't remember where I found this alias,
so I can't give proper credit.)&lt;/p&gt;
&lt;h2 id=&quot;force-vs-force-with-lease&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#force-vs-force-with-lease&quot;&gt;&lt;code&gt;--force&lt;/code&gt; vs &lt;code&gt;--force-with-lease&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Git's manual is too wordy,
so I'm relying on the answers to
&lt;a href=&quot;https://stackoverflow.com/q/52823692/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;&lt;code&gt;git push --force-with-lease&lt;/code&gt; vs &lt;code&gt;--force&lt;/code&gt;&lt;/em&gt; on Stack Overflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;chevybow writes (slightly modified and shortened):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;--force&lt;/code&gt; overwrites a remote branch with your local branch.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--force-with-lease&lt;/code&gt; is a safer option
that will not overwrite any work on the remote branch
if more commits were added to the remote branch
(by another team member or coworker or what have you).
It ensures you don't overwrite someone else's work by force pushing.&lt;/p&gt;
&lt;p&gt;I just think of &lt;code&gt;--force-with-lease&lt;/code&gt; as the option to use
when I want to make sure I don't overwrite any teammate's code.
A lot of teams at my company use &lt;code&gt;--force-with-lease&lt;/code&gt; as the default option for a fail-safe.
It's unnecessary in most circumstances
but will save you lots of headache
if you happen to overwrite something that another person contributed to remote.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;warning-fetching-is-risky&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#warning-fetching-is-risky&quot;&gt;Warning: fetching is risky&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;G. Sylvie Davies writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There's a sad implication here:
since &lt;code&gt;git fetch&lt;/code&gt; updates all refs under &amp;quot;refs/remotes/origin/*&amp;quot; to their latest versions,
this combination of commands is essentially identical to &lt;code&gt;git push --force&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; fetch

&lt;span class=&quot;token comment&quot;&gt;# The command below behaves identically to &quot;git push --force&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# if a &quot;git fetch&quot; just happened!&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push --force-with-lease
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To work around this inherent weakness in &lt;code&gt;git push --force-with-lease&lt;/code&gt;
I try to never run &lt;code&gt;git fetch&lt;/code&gt;.
Instead I always run &lt;code&gt;git pull --rebase&lt;/code&gt;
whenever I need to sync with upstream,
since &lt;code&gt;git pull&lt;/code&gt; only updates a single ref under refs/remotes,
keeping the &amp;quot;lease&amp;quot; of &lt;code&gt;--force-with-lease&lt;/code&gt; useful.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Does your code editor or IDE do automatic fetching?
You might want to disable that
unless you can accept the risk.&lt;/p&gt;
&lt;h2 id=&quot;when-to-force-push-with-lease&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#when-to-force-push-with-lease&quot;&gt;When to force push (with lease)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some say that one should never force push.
I say that's bollocks.&lt;/p&gt;
&lt;p&gt;If you are working on your own short-lived branch (not &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;main&lt;/code&gt;),
feel free to rewrite its history:
rebase, squash etc.
After rewriting a branch's history,
a force push is needed.&lt;/p&gt;
&lt;p&gt;The &amp;quot;if&amp;quot; in the previous paragraph is a misnomer.
&lt;em&gt;Of course&lt;/em&gt; you are working on short-lived branches
and not directly on the &lt;code&gt;master&lt;/code&gt;/&lt;code&gt;main&lt;/code&gt; branch,
right?
If you are not yet doing
&lt;a href=&quot;https://trunkbaseddevelopment.com/&quot; class=&quot;link link-external&quot;&gt;trunk-based development&lt;/a&gt;,
look it up.&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-undo-the-last-previous-most-recent-commit-in-git/</id><title>How to undo the last / previous / most recent commit in Git</title><link href="https://mtsknn.fi/blog/how-to-undo-the-last-previous-most-recent-commit-in-git/" /><published>2021-01-02T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="Git"></category><content type="html">&lt;p&gt;Run &lt;code&gt;git reset HEAD~&lt;/code&gt; or alias it to &lt;code&gt;git undo&lt;/code&gt;.
Bonus: how to use the commit message from the undoed commit.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#tldr&quot;&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Undo the last/previous/most recent commit
&lt;em&gt;while preserving the changes&lt;/em&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Keep the undoed changes&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; reset HEAD~

&lt;span class=&quot;token comment&quot;&gt;# or&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Keep the undoed changes in the staging area&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; reset HEAD~ --soft
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Afterwards,
to do a commit and use the commit message from the undoed commit:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit -c ORIG_HEAD
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If using
&lt;a href=&quot;https://github.com/mtsknn/dotfiles/blob/master/.gitconfig&quot; class=&quot;link link-external&quot;&gt;my Git aliases&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; undo
&lt;span class=&quot;token comment&quot;&gt;# or&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; undo --soft

&lt;span class=&quot;token comment&quot;&gt;# Use the commit message from the undoed commit&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; redo
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;explanation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#explanation&quot;&gt;Explanation&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;undoing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#undoing&quot;&gt;Undoing&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HEAD&lt;/code&gt; is your current &amp;quot;position&amp;quot; in Git's history;
it points to the commit that you have currently checked out.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HEAD~&lt;/code&gt; points to &lt;code&gt;HEAD&lt;/code&gt;'s parent commit,
i.e. to the previous commit of your current position.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git reset HEAD~&lt;/code&gt; resets the head to &lt;code&gt;HEAD~&lt;/code&gt;,
i.e. to the previous commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From &lt;a href=&quot;https://git-scm.com/docs/git-reset&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;git reset&lt;/code&gt;'s documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-bash bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; reset &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;mode&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 operator&quot;&gt;&amp;lt;&lt;/span&gt;commit&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This form resets the current branch head to &lt;code&gt;&amp;lt;commit&amp;gt;&lt;/code&gt;
and possibly updates the index (resetting it to the tree of &lt;code&gt;&amp;lt;commit&amp;gt;&lt;/code&gt;)
and the working tree depending on &lt;code&gt;&amp;lt;mode&amp;gt;&lt;/code&gt;.
If &lt;code&gt;&amp;lt;mode&amp;gt;&lt;/code&gt; is omitted,
defaults to &lt;code&gt;--mixed&lt;/code&gt;.
The &lt;code&gt;&amp;lt;mode&amp;gt;&lt;/code&gt; must be one of the following:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;--soft&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Does not touch the index file or the working tree at all
(but resets the head to &lt;code&gt;&amp;lt;commit&amp;gt;&lt;/code&gt;, just like all modes do).
This leaves all your changed files &amp;quot;Changes to be committed&amp;quot;,
as &lt;code&gt;git status&lt;/code&gt; would put it.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;--mixed&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Resets the index but not the working tree
(i.e., the changed files are preserved but not marked for commit)
and reports what has not been updated.
This is the default action.&lt;/dd&gt;
&lt;/dl&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;quot;The index&amp;quot; refers to the staging area
(the &amp;quot;Changes to be committed&amp;quot; area).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--mixed&lt;/code&gt; is the default mode,
so &lt;code&gt;git reset HEAD~&lt;/code&gt; resets the index,
meaning that the undoed changes are not kept in the staging area
(but the changes are preserved).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git reset HEAD~ --soft&lt;/code&gt; on the other hand
doesn't touch the index file,
meaning that the undoed changes &lt;em&gt;are&lt;/em&gt; kept in the staging area.&lt;/p&gt;
&lt;p&gt;Should you use the &lt;code&gt;--soft&lt;/code&gt; flag?
Depends on whether you want the undoed changes to be in the staging area.&lt;/p&gt;
&lt;h3 id=&quot;redoing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#redoing&quot;&gt;Redoing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;From &lt;a href=&quot;https://git-scm.com/docs/git-commit&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;git commit&lt;/code&gt;'s documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;-C &amp;lt;commit&amp;gt;&lt;/code&gt;&lt;/dt&gt;
&lt;dt&gt;&lt;code&gt;--reuse-message=&amp;lt;commit&amp;gt;&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Take an existing commit object,
and reuse the log message
and the authorship information (including the timestamp)
when creating the commit.
&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;-c &amp;lt;commit&amp;gt;&lt;/code&gt;&lt;/dt&gt;
&lt;dt&gt;&lt;code&gt;--reedit-message=&amp;lt;commit&amp;gt;&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;
Like &lt;code&gt;-C&lt;/code&gt;,
but with &lt;code&gt;-c&lt;/code&gt; the editor is invoked,
so that the user can further edit the commit message.
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/blockquote&gt;
&lt;p&gt;From &lt;a href=&quot;https://git-scm.com/docs/gitrevisions&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;gitrevisions&lt;/code&gt;'s documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ORIG_HEAD&lt;/code&gt; is created by commands that move your &lt;code&gt;HEAD&lt;/code&gt; in a drastic way,
to record the position of the &lt;code&gt;HEAD&lt;/code&gt; before their operation,
so that you can easily change the tip of the branch
back to the state before you ran them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words,
&lt;code&gt;ORIG_HEAD&lt;/code&gt; points to the previous &lt;code&gt;HEAD&lt;/code&gt; –
in this case to the undoed commit.&lt;/p&gt;
&lt;p&gt;Thus,
&lt;code&gt;git commit -c ORIG_HEAD&lt;/code&gt;
uses the commit message from the undoed commit
and opens the editor so you can edit the message before committing.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-commit&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;git commit&lt;/code&gt;'s documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-reset&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;git reset&lt;/code&gt;'s documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/gitrevisions&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;gitrevisions&lt;/code&gt;'s documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/2304087/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;What is &lt;code&gt;HEAD&lt;/code&gt; in Git?&lt;/em&gt; on Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/q/2221658/1079869&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;What's the difference between &lt;code&gt;HEAD^&lt;/code&gt; and &lt;code&gt;HEAD~&lt;/code&gt; in Git?&lt;/em&gt; on Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-chunk-an-array-in-javascript/</id><title>How to chunk an array in JavaScript</title><link href="https://mtsknn.fi/blog/how-to-chunk-an-array-in-javascript/" /><published>2021-01-01T12:00:00+03:00</published><updated>2021-06-12T12:00:00+03:00</updated><category term="JavaScript"></category><content type="html">&lt;p&gt;A simple reducer
to chunk (split) an array into smaller arrays.&lt;/p&gt;
&lt;p&gt;For example, with a chunk size of 3:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After&lt;/span&gt;
&lt;span class=&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 number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&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 number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&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 number&quot;&gt;10&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's how:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;chunk&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&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;
  array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&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;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; size &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; size&lt;span class=&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; acc
  &lt;span class=&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;// Usage:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; numbers &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 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;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&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; chunked &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chunk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;numbers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
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;chunked&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At every &lt;em&gt;nth&lt;/em&gt; iteration (where &lt;em&gt;n&lt;/em&gt; = &lt;code&gt;size&lt;/code&gt;; starting at the first iteration),
the accumulator array (&lt;code&gt;acc&lt;/code&gt;)
is appended with a chunk of the array (&lt;code&gt;array.slice(i, i + size)&lt;/code&gt;)
and then returned.
At other iterations,
the accumulator array is returned as-is.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;size&lt;/code&gt; is zero,
the method returns an empty array.
If &lt;code&gt;size&lt;/code&gt; is negative,
the method returns broken results.
So, if needed in your case,
you may want to do something about negative or non-positive &lt;code&gt;size&lt;/code&gt; values.&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flems.io/#0=N4IgtglgJlA2CmIBcBGADGgNCAZhBAzsgNqgB2AhmIkiAHQBWR2AxgPZkAu8XyI7ZApwAELABYBXMgGthAXmEAKCgCcVFAJ6ZhBCAC94ASnkA+ADplhw1eo10V8KBJbxFyli20B9bRGNyTYWALKysIHCUIYQBSHX14eTkFNGMKDzoABwkCMWU1TToCWAgXRQhfYQBqOINDQxDQh04JFUs0lgaAX21iAF16sgsAeiHhAFUCCgBzeCQLASFhMgkwACN4FQJ5YWIUbQAmbQBmbQAWbQBWbQA2bQB2bQAObQBObXRe+Y5F8SlpR22vxkimWaw2BGOAwWbAQdFgbCmiiB-ygAxA2AI8AQLE4EG+fBeSH2aBAnV6nSAA&quot; class=&quot;link link-external&quot;&gt;Test the code on flems.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/60779547/1079869&quot; class=&quot;link link-external&quot;&gt;More info in my Stack Overflow answer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-bypass-episervers-content-delivery-api-when-doing-ajax-requests/</id><title>How to bypass Episerver's Content Delivery API when doing Ajax requests</title><link href="https://mtsknn.fi/blog/how-to-bypass-episervers-content-delivery-api-when-doing-ajax-requests/" /><published>2020-12-23T12:00:00+03:00</published><updated>2020-12-23T12:00:00+03:00</updated><category term="C#"></category><category term="Episerver"></category><category term="JavaScript"></category><content type="html">&lt;p&gt;Requests with the &lt;code&gt;Accept&lt;/code&gt; header set to &lt;code&gt;application/json&lt;/code&gt;
are automatically routed to Content Delivery API.
Here's how to bypass it
and make the request go to a page controller instead.&lt;/p&gt;
&lt;p&gt;Starting from Content Delivery API version 2.3.0,
requests with the &lt;code&gt;Accept&lt;/code&gt; header set to &lt;code&gt;application/json&lt;/code&gt;
are automatically routed to Content Delivery API.
This is called
&lt;a href=&quot;https://world.episerver.com/documentation/developer-guides/content-delivery-api/using-friendly-urls/&quot; class=&quot;link link-external&quot;&gt;&amp;quot;Using friendly URLs&amp;quot; in the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a nice feature.
But what if you want to make an Ajax request to a page controller instead?
For example,
if you have a Single Page Application,
you might want to retrieve the next page's data in JSON format
from the page type's controller
using an Ajax request.&lt;/p&gt;
&lt;p&gt;In the controller
you can do something like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyPageController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;PageController&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;MyPage&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;ActionResult&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MyPage&lt;/span&gt; currentPage&lt;span class=&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsAjaxRequest&lt;/span&gt;&lt;span class=&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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&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 function&quot;&gt;Json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token 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 function&quot;&gt;View&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;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;MyPageViewModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentPage&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;But&lt;/em&gt;,
because the Ajax request's &lt;code&gt;Accept&lt;/code&gt; header will be set to &lt;code&gt;application/json&lt;/code&gt;,
the request will be automatically routed to Content Delivery API,
and the request will never reach the controller.&lt;/p&gt;
&lt;p&gt;The value of the &lt;code&gt;Accept&lt;/code&gt; header
can't be changed to another &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types&quot; class=&quot;link link-external&quot;&gt;MIME type&lt;/a&gt;
if the desired format for the response data is JSON.
So what to do?&lt;/p&gt;
&lt;p&gt;Turns out that
&lt;strong&gt;it's possible to specify
a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Quality_values&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;relative quality value&lt;/em&gt;&lt;/a&gt;
for the MIME type&lt;/strong&gt;:
&lt;code&gt;application/json;q=1&lt;/code&gt;.
From MDN:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Quality values&lt;/strong&gt;,
or &lt;em&gt;q-values&lt;/em&gt; and &lt;em&gt;q-factors&lt;/em&gt;,
are used to describe the order of priority of values
in a comma-separated list.
It is a special syntax allowed
in some &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers&quot; class=&quot;link link-external&quot;&gt;HTTP headers&lt;/a&gt;
and in HTML.
The importance of a value is marked by the suffix &lt;code&gt;';q='&lt;/code&gt;
immediately followed by a value between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; included,
with up to three decimal digits,
the highest value denoting the highest priority.
When not present, the default value is &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that the value of the &lt;code&gt;Accept&lt;/code&gt; header
doesn't strictly equal to &lt;code&gt;application/json&lt;/code&gt;,
the request is not routed to Content Delivery API.
Instead, it reaches the controller.
Egg-cellent!&lt;/p&gt;
&lt;p&gt;Since only one MIME type is specified,
and since the default quality value is anyway &lt;code&gt;1&lt;/code&gt;,
appending &lt;code&gt;;q=1&lt;/code&gt; to the &lt;code&gt;Accept&lt;/code&gt; header's value
doesn't have any side effects.&lt;/p&gt;
&lt;p&gt;You should probably document this somewhere.
For example,
if you are using &lt;code&gt;fetch()&lt;/code&gt;,
you can write something like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getPageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&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 keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&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;headers&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 comment&quot;&gt;// Requests with the `Accept` header set to `application/json`&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// are automatically routed to Content Delivery API.&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// The `;q=1` here is a &quot;relative quality value&quot;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// and doesn't have any effects other than&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// tricking the request to go to the controller&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// instead of Content Delivery API.&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;Accept&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'application/json;q=1'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&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;then&lt;/span&gt;&lt;span class=&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;response&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; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way some overly enthusiastic developer
won't remove the quality value
thinking that it's unnecessary
(since there's only one MIME type
and since the default quality value is anyway &lt;code&gt;1&lt;/code&gt;).&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/tfa-stands-for-the-featured-article/</id><title>TFA stands for &quot;The Featured Article&quot;</title><link href="https://mtsknn.fi/blog/tfa-stands-for-the-featured-article/" /><published>2020-12-01T12:00:00+03:00</published><updated>2020-12-01T12:00:00+03:00</updated><category term="English"></category><content type="html">&lt;p&gt;And RTFA/RTFM stands for &amp;quot;Read The Fine Article/Manual.&amp;quot;
Who likes profanity, anyway?&lt;/p&gt;
&lt;p&gt;Some people on sites like Reddit and Hacker News
tend to use the abbreviation TFA
to refer to the discussed article.
If the comment is otherwise
non-negative or even positive,
I'm always baffled –
why the hostility?
Why the profanity?&lt;/p&gt;
&lt;p&gt;Luckily,
with some quick googling,
I found that the letter &amp;quot;F&amp;quot; in the abbreviations TFA, RTFA and RTFM
can be interpreted as &amp;quot;fine&amp;quot; or &amp;quot;featured.&amp;quot;
Genius!
Now I don't have to get triggered
from reading other people's comments on the Internet.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Bonus:
&lt;a href=&quot;https://developer.android.com/reference/android/util/Log&quot; class=&quot;link link-external&quot;&gt;Android's &lt;code&gt;Log&lt;/code&gt; util&lt;/a&gt;
has &lt;code&gt;Log.d()&lt;/code&gt;, &lt;code&gt;Log.e()&lt;/code&gt;, &lt;code&gt;Log.i()&lt;/code&gt;, &lt;code&gt;Log.v()&lt;/code&gt; and &lt;code&gt;Log.w()&lt;/code&gt; methods
for different levels of logging:
debug, error, information, verbose and warning, respectively.
And there's one more:
&lt;a href=&quot;https://developer.android.com/reference/android/util/Log#wtf(java.lang.String,%20java.lang.String)&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;Log.wtf()&lt;/code&gt;&lt;/a&gt;
to &amp;quot;report an exception that should never happen.&amp;quot;
But what does &amp;quot;wtf&amp;quot; mean here?
&lt;em&gt;What a terrible failure.&lt;/em&gt;
Terrific!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/rfc-2119-in-a-nutshell/</id><title>RFC 2119 in a nutshell</title><link href="https://mtsknn.fi/blog/rfc-2119-in-a-nutshell/" /><published>2020-11-17T12:00:00+03:00</published><updated>2021-05-11T12:00:00+03:00</updated><category term="Miscellaneous"></category><content type="html">&lt;p&gt;RFC 2119 defines key words such as
&amp;quot;MUST,&amp;quot; &amp;quot;MUST NOT,&amp;quot; &amp;quot;REQUIRED&amp;quot; and &amp;quot;SHALL&amp;quot;
that are often used in specifications.
Here's a summary of the key word definitions.&lt;/p&gt;
&lt;p&gt;Some specifications,
like &lt;a href=&quot;https://sembr.org/&quot; class=&quot;link link-external&quot;&gt;Semantic Line Breaks&lt;/a&gt;
and &lt;a href=&quot;https://semver.org/&quot; class=&quot;link link-external&quot;&gt;Semantic Versioning&lt;/a&gt;,
include this piece of text at the beginning –
as RECOMMENDED by &lt;a href=&quot;https://www.ietf.org/rfc/rfc2119.txt&quot; class=&quot;link link-external&quot;&gt;RFC 2119&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The key words &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL
NOT&amp;quot;, &amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and
&amp;quot;OPTIONAL&amp;quot; in this document are to be interpreted as described in
RFC 2119.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's a summary of what each of the key words mean:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;MUST = REQUIRED = SHALL&lt;/dt&gt;
&lt;dd&gt;An absolute requirement.&lt;/dd&gt;
&lt;dt&gt;MUST NOT = SHALL NOT&lt;/dt&gt;
&lt;dd&gt;An absolute prohibition.&lt;/dd&gt;
&lt;dt&gt;SHOULD = RECOMMENDED&lt;/dt&gt;
&lt;dd&gt;Ignore only with good reasons.&lt;/dd&gt;
&lt;dt&gt;SHOULD NOT = NOT RECOMMENDED&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/dt&gt;
&lt;dd&gt;Ignore only with good reasons.&lt;/dd&gt;
&lt;dt&gt;MAY = OPTIONAL&lt;/dt&gt;
&lt;dd&gt;Truly optional,
but if included,
the implementation MUST be interoperable
with another implementation
which does not include the option,
and vice versa.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The RFC also raises these points for specification authors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The key words MUST be used only
when required
for interoperability
or limiting potentially harmful behavior.&lt;/li&gt;
&lt;li&gt;The security implications
between MUST and SHOULD,
as well as between MUST NOT and SHOULD NOT,
may be very subtle,
so the differences SHOULD&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; be elaborated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now go
&lt;a href=&quot;https://www.ietf.org/rfc/rfc2119.txt&quot; class=&quot;link link-external&quot;&gt;read the RFC&lt;/a&gt;,
it's actually very short and clear.&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;The key word &amp;quot;NOT RECOMMENDED&amp;quot;
is missing from the recommended introductory phrase,
but it's paired with &amp;quot;SHOULD NOT&amp;quot; in the RFC. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;The word &amp;quot;should&amp;quot; is not capitalized in this part of the RFC,
but it seems like a missed opportunity
so I capitalized it. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/hyperscript-hyperior-alternative-to-jsx/</id><title>Hyperscript: hyperior alternative to JSX</title><link href="https://mtsknn.fi/blog/hyperscript-hyperior-alternative-to-jsx/" /><published>2020-11-03T12:00:00+03:00</published><updated>2020-12-27T12:00:00+03:00</updated><category term="JavaScript"></category><category term="Mithril.js"></category><category term="React"></category><content type="html">&lt;p&gt;JSX is just JS under the hood.
Hyperscript is like that JS,
but better.
Example:
&lt;code&gt;h('a.link', { href }, 'Click me')&lt;/code&gt;
is nicer than
&lt;code&gt;&amp;lt;a className=&amp;quot;link&amp;quot; href={href}&amp;gt;Click me&amp;lt;/a&amp;gt;&lt;/code&gt;,
right? Right?!&lt;/p&gt;
&lt;h2 id=&quot;how-jsx-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-jsx-works&quot;&gt;How JSX works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JSX is not valid JS –
it's a syntax extension to JS.
Let's consider the following imaginary React component written using JSX:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-jsx bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; links &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token 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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;header&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;my-header&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&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;header&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 plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&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;logo&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 plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/&lt;span class=&quot;token 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 plain-text&quot;&gt;mtsknn.fi&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&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;header__links&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 plain-text&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; href&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&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&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&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&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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 plain-text&quot;&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;DarkModeToggle&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 plain-text&quot;&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;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&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;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code gets compiled by Babel before it's served to the browser&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;,
so that JSX gets replaced with &lt;code&gt;React.createElement()&lt;/code&gt; function invocations&lt;sup&gt;&lt;a aria-label=&quot;footnote 2&quot; class=&quot;link&quot; href=&quot;#fn-2&quot; id=&quot;fnref-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; links &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token 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;
    React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'header'&lt;/span&gt;&lt;span class=&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;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'my-header'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'header'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'div'&lt;/span&gt;&lt;span class=&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;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'logo'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&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;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'mtsknn.fi'&lt;/span&gt;&lt;span class=&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;
      React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'nav'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul'&lt;/span&gt;&lt;span class=&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;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'header__links'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; href&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&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;key&lt;/span&gt;&lt;span class=&quot;token operator&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;
              React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&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;href&lt;/span&gt;&lt;span class=&quot;token operator&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; text&lt;span class=&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;
          React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DarkModeToggle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token 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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uh, that's a bit annoying to read.
Let's make that a bit more readable
by assigning &lt;code&gt;React.createElement()&lt;/code&gt; to a new variable &lt;code&gt;h&lt;/code&gt;.
(&amp;quot;h&amp;quot; as in hyperscript –
though note that this is not yet proper hyperscript.)
Let's also simplify &lt;code&gt;{ href: href }&lt;/code&gt; into &lt;code&gt;{ href }&lt;/code&gt; because OCD:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createElement &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; h &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; links &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token 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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'header'&lt;/span&gt;&lt;span class=&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;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'my-header'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'header'&lt;/span&gt; &lt;span class=&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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'div'&lt;/span&gt;&lt;span class=&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;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'logo'&lt;/span&gt; &lt;span class=&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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&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;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'mtsknn.fi'&lt;/span&gt;&lt;span class=&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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'nav'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul'&lt;/span&gt;&lt;span class=&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;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'header__links'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; href&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&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;key&lt;/span&gt;&lt;span class=&quot;token operator&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 function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &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; text&lt;span class=&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 function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DarkModeToggle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token 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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can more clearly see that&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the first argument of &lt;code&gt;React.createElement()&lt;/code&gt; is the tag name or component;&lt;/li&gt;
&lt;li&gt;the second argument is the &lt;code&gt;props&lt;/code&gt; object
(or &lt;code&gt;null&lt;/code&gt; if the element doesn't get any props);&lt;/li&gt;
&lt;li&gt;and the rest of the arguments are the children of the element.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, under the hood, JSX is just regular JS.
And it's not specific to React.
Babel could as well replace JSX with something else than &lt;code&gt;React.createElement()&lt;/code&gt; function invocations.&lt;/p&gt;
&lt;h2 id=&quot;what-hyperscript-is-and-looks-like&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#what-hyperscript-is-and-looks-like&quot;&gt;What hyperscript is and looks like&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I couldn't find a proper definition for hyperscript,
but think of it as the &lt;strong&gt;JS equivalent of JSX&lt;/strong&gt;.
You can use hyperscript to &lt;strong&gt;declare the structure of your (React) components in plain JS&lt;/strong&gt;.
Hyperscript is like the code in the previous code block, but better.&lt;/p&gt;
&lt;p&gt;Let's take a look at two real-world hyperscript implementations to see what they look like.&lt;/p&gt;
&lt;h3 id=&quot;example-1-react-with-react-hyperscript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-1-react-with-react-hyperscript&quot;&gt;Example 1: React with &lt;code&gt;react-hyperscript&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Looking at our previous code example,
it would be nice if we could at least:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;omit the second argument if it's &lt;code&gt;null&lt;/code&gt;.
This would make the code easier to read by reducing visual noise.&lt;/li&gt;
&lt;li&gt;optionally wrap the children in an array.
This would make indentation more logical and Prettier-compatible (is that a word?).
It would also allow you to use trailing commas if that's your thing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/mlmorg/react-hyperscript&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;react-hyperscript&lt;/code&gt; library&lt;/a&gt;
supports that.
It also supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using CSS selectors in the tag names to specify CSS classes and IDs.
For example,
&lt;code&gt;h('header#my-id.foo.bar')&lt;/code&gt;
is the same as
&lt;code&gt;h('header', { id: 'my-id', className: 'foo bar' })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;omitting the tag name if it's &lt;code&gt;div&lt;/code&gt;,
i.e. the default tag name is &lt;code&gt;div&lt;/code&gt;.
For example,
&lt;code&gt;h('.logo')&lt;/code&gt;
is the same as
&lt;code&gt;h('div.logo')&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's see what our component looks like when using &lt;code&gt;react-hyperscript&lt;/code&gt;:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; h &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'react-hyperscript'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; links &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token 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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'header#my-header.header'&lt;/span&gt;&lt;span class=&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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.logo'&lt;/span&gt;&lt;span class=&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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&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;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'/'&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'mtsknn.fi'&lt;/span&gt;&lt;span class=&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 function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'nav'&lt;/span&gt;&lt;span class=&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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul.header__links'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; href&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&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;key&lt;/span&gt;&lt;span class=&quot;token operator&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 function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &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; text&lt;span class=&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 function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&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;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DarkModeToggle&lt;span class=&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 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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That looks pretty good!
We got rid of &lt;code&gt;null&lt;/code&gt; props and some other prop objects as well by using CSS syntax.
Children that are not on the same line as their parent
are wrapped in arrays.
This makes the indentation clearer.&lt;/p&gt;
&lt;p&gt;(Side note:
at the end of the code example,
the &lt;code&gt;DarkModeToggle&lt;/code&gt; component needs to be in an array because
it's a component instead of a string.
There's an &lt;a href=&quot;https://github.com/mlmorg/react-hyperscript/issues/7&quot; class=&quot;link link-external&quot;&gt;open issue on GitHub&lt;/a&gt; about that.
Unfortunately the library hasn't received any updates in a couple of years,
but this issue is not a biggie.)&lt;/p&gt;
&lt;p&gt;To start using &lt;code&gt;react-hyperscript&lt;/code&gt;,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;run &lt;code&gt;npm install react-hyperscript&lt;/code&gt;
(or &lt;code&gt;npm i react-hyperscript&lt;/code&gt; for short)&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;import h from 'react-hyperscript'&lt;/code&gt; to your code&lt;/li&gt;
&lt;li&gt;start replacing that filthy JSX with the &lt;code&gt;h()&lt;/code&gt; function.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;example-2-mithril&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-2-mithril&quot;&gt;Example 2: Mithril&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://mithril.js.org/&quot; class=&quot;link link-external&quot;&gt;Mithril&lt;/a&gt;
is a small (&amp;lt;10kb gzip) yet mighty JS framework.
I prefer using Mithril over React in my own projects because it's so good.
(I should write a blog post about it.)&lt;/p&gt;
&lt;p&gt;Anyway, Mithril uses hyperscript by default.
Mithril's hyperscript flavor has two main extra features compared to &lt;code&gt;react-hyperscript&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Besides CSS classes and IDs,
you can also specify static attributes
in the tag name (first parameter)
using CSS syntax.
For example,
&lt;code&gt;m('a[href=/foo]')&lt;/code&gt; is the same as &lt;code&gt;m('a', { href: '/foo' })&lt;/code&gt;.
(Notice how Mithril uses &lt;code&gt;m()&lt;/code&gt; instead of &lt;code&gt;h()&lt;/code&gt;,
but that doesn't matter in practice.)&lt;/li&gt;
&lt;li&gt;It's more flexible about its input parameters –
children can be in an array,
but they don't have to.
In our header component example,
the &lt;code&gt;DarkModeToggle&lt;/code&gt; component doesn't need to be in an array
(unlike when using &lt;code&gt;react-hyperscript&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our component would look like this when using Mithril:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-js bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; m &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'mithril'&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; links &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token 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;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'header#my-header.header'&lt;/span&gt;&lt;span class=&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;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'.logo'&lt;/span&gt;&lt;span class=&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;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a[href=/]'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;'mtsknn.fi'&lt;/span&gt;&lt;span class=&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 function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'nav'&lt;/span&gt;&lt;span class=&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;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'ul.header__links'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; href&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&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;key&lt;/span&gt;&lt;span class=&quot;token operator&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 function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &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; text&lt;span class=&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 function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;'li'&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DarkModeToggle&lt;span class=&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 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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's almost identical than when using &lt;code&gt;react-hyperscript&lt;/code&gt;,
only a bit more terse.
(I have highlighted the two lines that are different.)
But being able to specify static attributes using CSS syntax is nifty,
especially when you have more of them;
the example header component has just one.
And the increased flexibility regarding the input parameters
means one thing less to worry about,
i.e. whether children need to be wrapped in arrays or not.&lt;/p&gt;
&lt;p&gt;Since Mithril uses hyperscript by default,
there's no steps to enable hyperscript.
Read the &lt;a href=&quot;https://mithril.js.org/simple-application.html&quot; class=&quot;link link-external&quot;&gt;Mithril tutorial&lt;/a&gt;
and start using it.&lt;/p&gt;
&lt;h2 id=&quot;pros-and-cons-of-hyperscript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pros-and-cons-of-hyperscript&quot;&gt;Pros and cons of hyperscript&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Okay, that's nice and all,
but why would you use hyperscript over JSX?&lt;/p&gt;
&lt;h3 id=&quot;pros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#pros&quot;&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here's a non-exhaustive list of the good sides of hyperscript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No need for context switching between JS and XML&lt;/strong&gt;
because hyperscript is just JavaScript.
&lt;ul&gt;
&lt;li&gt;Hyperscript could also make it easier to understand
how your JS framework of choice (be it React or Mithril or something else) works.
When learning React and JSX,
a possibly common frustration is
&amp;quot;why can't I use &lt;code&gt;if&lt;/code&gt; statements and &lt;code&gt;for&lt;/code&gt; loops in my JSX?&amp;quot;
When using hyperscript,
it's probably clearer
why you can't have &lt;code&gt;if&lt;/code&gt; statements and &lt;code&gt;for&lt;/code&gt; loops as function arguments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS classes and IDs can be specified in the tag name&lt;/strong&gt;
which leads to terser code.
Very nice when using e.g. &lt;a href=&quot;https://tailwindcss.com/&quot; class=&quot;link link-external&quot;&gt;Tailwind&lt;/a&gt;:
&lt;code&gt;h('img.h-16.md:h-24')&lt;/code&gt; etc.
&lt;ul&gt;
&lt;li&gt;In some flavors of hyperscript (e.g. Mithril),
other CSS-like shorthands are also possible,
like &lt;code&gt;m('a[href=/foo].bar.baz')&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hyperscript is &lt;strong&gt;less verbose&lt;/strong&gt; (CSS-like tag names, no closing tags).
This leads to shorter code –
without sacrificing readability if you ask me.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No need for JSX compilation.&lt;/strong&gt;
This leads to simpler tooling,
simpler build processes
and fewer dependencies.
&lt;ul&gt;
&lt;li&gt;You can start prototyping
without having to setup complex build processes et cetera.
(Though in the case of React,
using Create React App is also easy and quick.
But still much more complex!)&lt;/li&gt;
&lt;li&gt;Simpler tooling also means that
your code editor doesn't have to support or have plugins for
JSX parsing, highlighting etc.
Just open &lt;code&gt;notepad.exe&lt;/code&gt; and start hacking
like any advanced programmer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cons&quot;&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Hyperscript is &lt;strong&gt;not as common as JSX&lt;/strong&gt; (at least in the React world).
Unless you can convince your team to choose hyperscript,
JSX is likely the easier choice.
If you use JSX,
it might also be easier to
attract new developers to your team
due to familiarity.
Though learning hyperscript shouldn't be at all difficult.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The syntax might take some time to get used to.&lt;/strong&gt;
While hyperscript is just JavaScript,
there are a lot of different kinds of brackets.
But like said:
learning hyperscript shouldn't be difficult.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Because there aren't closing tags like in JSX,
you &lt;strong&gt;can't see as well where tags end&lt;/strong&gt;.
I haven't personally found this to be a problem though.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Android Studio solves this problem nicely for Flutter projects.
It automatically shows code comments
at the end of widgets (think of React components)
like this:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-dart bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyWidget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  child&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pinkAccent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    height&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    width&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    child&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Center&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      child&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;'Bacon ipsum'&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextStyle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;white&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          fontSize&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          fontWeight&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FontWeight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bold&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&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;// Text&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Center&lt;/span&gt;
  &lt;span class=&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;// Container&lt;/span&gt;
&lt;span class=&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;// MyWidget&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There's &lt;strong&gt;runtime overhead&lt;/strong&gt; of parsing the CSS-like selectors.
This is unlikely a major performance problem
unless you have lots of complex selectors,
but something to be aware of.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you use Mithril,
you can setup
a &lt;a href=&quot;https://github.com/mithriljs/mopt&quot; class=&quot;link link-external&quot;&gt;Babel plugin called &lt;code&gt;mopt&lt;/code&gt;&lt;/a&gt;
to statically optimize &lt;code&gt;m()&lt;/code&gt; function invocations.
Look ma, no more runtime overhead!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;bottom-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#bottom-line&quot;&gt;Bottom line&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hmm, looks I listed as many pros as I listed cons.
Didn't I say that hyperscript is hyperior?!&lt;/p&gt;
&lt;p&gt;If you ask me, the pros greatly outweight the cons.
Give my hyperscript over JSX any day, thank you.&lt;/p&gt;
&lt;p&gt;In the end it's a matter of personal preference
and what works for you and your team.
Because this is a personal blog,
I'm free to call hyperscript hyperior anyhow,
so checkmate, atheists. ;-)&lt;/p&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The React docs have a couple of pages about JSX:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/introducing-jsx.html&quot; class=&quot;link link-external&quot;&gt;Introducing JSX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/jsx-in-depth.html&quot; class=&quot;link link-external&quot;&gt;JSX In Depth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/react-without-jsx.html&quot; class=&quot;link link-external&quot;&gt;React Without JSX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mithril.js.org/jsx.html#jsx-vs-hyperscript&quot; class=&quot;link link-external&quot;&gt;Mithril docs' section about JSX vs hyperscript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ohanhi/hyperscript-helpers&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;hyperscript-helpers&lt;/code&gt;&lt;/a&gt;
and
&lt;a href=&quot;https://github.com/Jador/react-hyperscript-helpers&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;react-hyperscript-helpers&lt;/code&gt;&lt;/a&gt;
offer even terser hyperscript syntax.
I'm not a fan of this style,
but check them out,
you might like them.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thi-ng/umbrella/tree/develop/packages/hdom&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;@thi.ng/hdom&lt;/code&gt;&lt;/a&gt;
and &lt;a href=&quot;https://github.com/lukejacksonn/ijk&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;ijk&lt;/code&gt;&lt;/a&gt;
are hyperscript alternatives based on arrays.
I haven't tried these,
but they look interesting.&lt;/li&gt;
&lt;/ul&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;It's also possible to use Babel in the browser to compile code on the fly.
That would be slow and in most cases just unnecessary. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html&quot; class=&quot;link link-external&quot;&gt;React 17 introduced a new JSX transform&lt;/a&gt;
that makes the output look different.
This doesn't change the idea behind hyperscript. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/contenteditable-first-letter-chrome-buggy-combo/</id><title>`contenteditable` + `::first-letter` + Chrome = buggy combo</title><link href="https://mtsknn.fi/blog/contenteditable-first-letter-chrome-buggy-combo/" /><published>2020-10-13T12:00:00+03:00</published><updated>2021-11-30T12:00:00+03:00</updated><category term="CSS"></category><content type="html">&lt;p&gt;This combination causes weird behavior and data loss
because of a bug in Chrome,
so it's best not to use &lt;code&gt;contenteditable&lt;/code&gt; and &lt;code&gt;::first-letter&lt;/code&gt; together.&lt;/p&gt;
&lt;h2 id=&quot;whats-contenteditable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-contenteditable&quot;&gt;What's &lt;code&gt;contenteditable&lt;/code&gt;?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;contenteditable&lt;/code&gt; HTML attribute&lt;/a&gt;
makes an element's contents editable in the browser.&lt;/p&gt;
&lt;p&gt;Demo:&lt;/p&gt;
&lt;blockquote contenteditable&gt;&lt;p&gt;I'm a blockquote with the `contenteditable` attribute. Select and edit me!&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;For example,
&lt;a href=&quot;https://www.tiny.cloud/&quot; class=&quot;link link-external&quot;&gt;TinyMCE&lt;/a&gt;
is a WYSIWYG (&amp;quot;what you see is what you get&amp;quot;) HTML editor
that uses the &lt;code&gt;contenteditable&lt;/code&gt; attribute under the hood.&lt;/p&gt;
&lt;h2 id=&quot;whats-first-letter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-first-letter&quot;&gt;What's &lt;code&gt;::first-letter&lt;/code&gt;?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::first-letter&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;::first-letter&lt;/code&gt; CSS pseudo-element&lt;/a&gt;
can be used to stylize
&amp;quot;the first letter of the first line of a block-level element,
but only when not preceded by other content (such as images or inline tables).&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Initial&quot; class=&quot;link link-external&quot;&gt;&lt;em&gt;Initial&lt;/em&gt; on Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a written or published work,
an &lt;strong&gt;initial&lt;/strong&gt; or &lt;strong&gt;drop cap&lt;/strong&gt;
is a letter at the beginning of a word, a chapter, or a paragraph
that is larger than the rest of the text.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-css bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article &gt; p:first-child::first-letter&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Demo:&lt;/p&gt;
&lt;blockquote class=&quot;drop-cap-demo&quot;&gt;
&lt;p&gt;This paragraph has an initial / drop cap letter,
meaning that the first letter (&amp;quot;T&amp;quot;) should be large and bold.&lt;/p&gt;
&lt;p&gt;This paragraph has a regular first letter.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;whats-chrome&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#whats-chrome&quot;&gt;What's Chrome?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Just kidding, I know you know. 😄&lt;/p&gt;
&lt;h2 id=&quot;example-use-case-for-the-combination&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#example-use-case-for-the-combination&quot;&gt;Example use case for the combination&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Your website shows drop cap letters (&lt;code&gt;::first-letter&lt;/code&gt;) somewhere.&lt;/li&gt;
&lt;li&gt;Your website's content creators create content with TinyMCE
(which uses the &lt;code&gt;contenteditable&lt;/code&gt; attribute under the hood).&lt;/li&gt;
&lt;li&gt;The TinyMCE editor has been stylized (using CSS) to show drop cap letters
so that the content looks the same in the TinyMCE editor and on the live site.&lt;/li&gt;
&lt;li&gt;Your website's content creators use Chrome.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's how you end up with the buggy combination that's
&lt;code&gt;contenteditable&lt;/code&gt; + &lt;code&gt;::first-letter&lt;/code&gt; + Chrome.&lt;/p&gt;
&lt;h2 id=&quot;problems-with-the-combination&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#problems-with-the-combination&quot;&gt;Problems with the combination&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Note:
in my case I had a TinyMCE editor
in which the first paragraph had a drop cap letter
and other paragraphs were normal (no drop caps).
In other cases the problems might be different.&lt;/p&gt;
&lt;p&gt;Also note:
the problems are not related to TinyMCE per se;
it just happens to use the &lt;code&gt;contenteditable&lt;/code&gt; attribute under the hood.&lt;/p&gt;
&lt;h3 id=&quot;incorrect-caret-position&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#incorrect-caret-position&quot;&gt;Incorrect caret position&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the caret is in the drop cap paragraph,
the caret's position is one character too much to the right.
This is confusing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update in November 2021:&lt;/strong&gt;
this seems to no longer be an issue as of Chrome 95
(though I don't know in which version the issue has been fixed).&lt;/p&gt;
&lt;h3 id=&quot;minor-data-loss&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#minor-data-loss&quot;&gt;Minor data loss&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the caret is at the end of the first paragraph,
pressing &lt;kbd&gt;Delete&lt;/kbd&gt; &lt;strong&gt;removes two characters&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the line break between the paragraphs&lt;/li&gt;
&lt;li&gt;the last character of the first paragraph.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Normally only the line break between the paragraphs should be removed,
so that the contents of the second paragraph
are moved to the end of the first paragraph.&lt;/p&gt;
&lt;p&gt;The same issue happens (two characters are removed instead of one)
when the caret is at the beginning of the second paragraph
and &lt;kbd&gt;Backspace&lt;/kbd&gt; is pressed.&lt;/p&gt;
&lt;p&gt;In addition to causing minor data loss,
this buggy behavior is also confusing.&lt;/p&gt;
&lt;p&gt;Extra confusion:
if the drop cap covers more than one character&lt;sup&gt;&lt;a aria-label=&quot;footnote 1&quot; class=&quot;link&quot; href=&quot;#fn-1&quot; id=&quot;fnref-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;,
the operations above remove more than one extra character.&lt;/p&gt;
&lt;h3 id=&quot;major-data-loss&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#major-data-loss&quot;&gt;Major data loss&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the caret is at the end of the drop cap paragraph,
pressing &lt;kbd&gt;Backspace&lt;/kbd&gt; &lt;strong&gt;empties the whole paragraph&lt;/strong&gt;!
Looking at Chrome DevTools,
the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag is still there,
but it's empty.&lt;/p&gt;
&lt;p&gt;Normally only the last character of the paragraph should be removed.&lt;/p&gt;
&lt;p&gt;The same issue happens (the whole paragraph is emptied)
when the caret is at the second last position of the first paragraph
and &lt;kbd&gt;Delete&lt;/kbd&gt; is pressed.&lt;/p&gt;
&lt;p&gt;In addition to causing major data loss,
this buggy behavior is also confusing.&lt;/p&gt;
&lt;h2 id=&quot;the-root-cause-a-bug-in-chrome&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-root-cause-a-bug-in-chrome&quot;&gt;The root cause: a bug in Chrome&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Long story short:
this is a bug in Chrome.
The &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=174349&quot; class=&quot;link link-external&quot;&gt;&amp;quot;Contenteditable with :first-letter styling&amp;quot; Chromium issue&lt;/a&gt;
was reported in 2013 (almost 9 years ago as of November 2021)
and hasn't been fixed yet.&lt;/p&gt;
&lt;h2 id=&quot;the-fix-dont-use-the-combination&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-fix-dont-use-the-combination&quot;&gt;The fix: don't use the combination&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In practice you should avoid using
the &lt;code&gt;contenteditable&lt;/code&gt; HTML attribute
and the &lt;code&gt;::first-letter&lt;/code&gt; CSS pseudo-element together.&lt;/p&gt;
&lt;p&gt;Avoiding the bug might not be a &amp;quot;fix&amp;quot; per se,
but since the bug is in Chrome itself,
there's not much else to do.&lt;/p&gt;
&lt;h2 id=&quot;how-i-investigated-the-issue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-i-investigated-the-issue&quot;&gt;How I investigated the issue&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was a simple 30-minute investigation,
but I hope that this short story will be helpful to some
by showing one way of investigating these kind of bugs.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I first tested
what styles of the &lt;code&gt;::first-letter&lt;/code&gt; pseudo-element cause the problems
by tweaking the styles of the buggy TinyMCE editor in Chrome DevTools.
After quick fiddling,
it was apparent that any single valid style causes the problems.
Because of this,
it looked unlikely that the issue was in the CSS styles.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thinking that this was an issue in TinyMCE,
I googled for queries like &amp;quot;tinymce first-letter&amp;quot;
to look for bug reports and solutions.
But all I could find was
&lt;a href=&quot;https://github.com/tinymce/tinymce/issues/2891&quot; class=&quot;link link-external&quot;&gt;one TinyMCE issue on GitHub from 2016&lt;/a&gt;
which was closed in 2018 without a solution.
&amp;quot;It seems to be a problem with CSS and not TinyMCE itself&amp;quot; they said.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hmm, what could I try next...
I was using TinyMCE version 4 and the latest was version 5.
So maybe the issue had been fixed ages ago (in TinyMCE version 5)
and everyone had already upgraded to version 5,
so that's why no one was talking about this?
Note that I was still thinking that the issue was in TinyMCE.&lt;/p&gt;
&lt;p&gt;Well, let's try.
I remembered that there was a live demo of TinyMCE
&lt;a href=&quot;https://www.tiny.cloud/&quot; class=&quot;link link-external&quot;&gt;on TinyMCE's homepage&lt;/a&gt;
(update: the demos are not anymore on the homepage as of November 2021).
I added drop cap stylings to the demo using Chrome DevTools, and...
Bleh, version 5 had the same problems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But wait!
While tweaking the styles,
I noticed that the TinyMCE demo used the &lt;code&gt;contenteditable&lt;/code&gt; attribute.
Could it be that this was not a styling issue
(despite the GitHub issue suggesting otherwise)
but related to the &lt;code&gt;contenteditable&lt;/code&gt; attribute?&lt;/p&gt;
&lt;p&gt;I created a
&lt;a href=&quot;https://flems.io/#0=N4IgzgpgNhDGAuEAmIBcIB0ALeBbKIANCAGYCWMYaA2qAHYCGuEamO+RIsA9nYn6wA8YeAE8YAPgA6dAASyAxACdu3eLOAz58gEbclSCEtSyAjAAcAHrLDcoZJLKxrzZOgGsA3Fu3mGSJDcAcxMABjMIXG85WQBfH2VVdQlZc1RyJREAWlgsCiRUdLJM+CyYeEQlDR95El5SkiYKURMwBjowLMglMhJo7Vk6vi6yAC8IEwAmSP7tIdKAdwgyIJwTPSgkWfi6QQB6EXEIaV3AgDdZHj4Ia8D4Bh0YWQcAXikQFTV3k-lBcwkAKJ3WTMACE+3+Pj+gOBCmY8FUEJO+3OEhAsQAurEgA&quot; class=&quot;link link-external&quot;&gt;quick 2-minute fiddle of the &lt;code&gt;contenteditable&lt;/code&gt; + &lt;code&gt;::first-letter&lt;/code&gt; combo at flems.io&lt;/a&gt; –
and voilà!
My quick fiddle had the same problems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Because the &lt;code&gt;contenteditable&lt;/code&gt; attribute is more common than TinyMCE,
I now had higher hopes of finding relevant results.
When googling for &amp;quot;contenteditable first-letter,&amp;quot;
&lt;a href=&quot;https://stackoverflow.com/q/18397450/1079869&quot; class=&quot;link link-external&quot;&gt;the first SO question that I opened&lt;/a&gt;
had this snippet of wisdom in the top-voted answer by Marc J (thanks Marc!):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I just noticed that there is a
&lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=174349&quot; class=&quot;link link-external&quot;&gt;bug in Chrome&lt;/a&gt;
that causes the cursor to become in the wrong spot
with &lt;code&gt;contenteditable&lt;/code&gt; and &lt;code&gt;::first-letter&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that was it!
Some fiddling, googling, and a little bit of luck.&lt;/p&gt;

  &lt;hr aria-hidden=&quot;true&quot;&gt;
  &lt;section aria-label=&quot;Footnotes&quot;&gt;
    &lt;h2 class=&quot;!text-base !text-gray-700 tracking-widest uppercase xl:!text-lg&quot;&gt;
      Footnotes
    &lt;/h2&gt;
    &lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;p&gt;If a drop cap paragraph starts e.g. with the word &amp;quot;I'm,&amp;quot;
the drop cap covers both the letter &amp;quot;I&amp;quot; and the apostrophe.
&amp;quot;The first letter of an element is not always trivial to identify,&amp;quot;
as mentioned on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::first-letter&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;::first-letter&lt;/code&gt; page on MDN&lt;/a&gt;. &lt;a aria-label=&quot;Back to reference&quot; class=&quot;font-mono link&quot; href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-change-modified-date-programmatically-in-episerver/</id><title>How to change Modified date programmatically in Episerver</title><link href="https://mtsknn.fi/blog/how-to-change-modified-date-programmatically-in-episerver/" /><published>2020-10-08T12:00:00+03:00</published><updated>2021-10-28T12:00:00+03:00</updated><category term="C#"></category><category term="Episerver"></category><content type="html">&lt;p&gt;When migrating content from another platform to Episerver,
I wanted to set a specific datetime for each content's Modified date (&lt;code&gt;Saved&lt;/code&gt; property).
Sounds simple,
but it was only possible by using Episerver's internal, undocumented API.&lt;/p&gt;
&lt;h2 id=&quot;how-to-do-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-to-do-it&quot;&gt;How to do it&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;setting-the-current-date&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#setting-the-current-date&quot;&gt;Setting the current date&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This should be straightforward.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set a content's &lt;code&gt;SetChangedOnPublish&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;:&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IChangeTrackable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SetChangedOnPublish &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Publish the content.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From
&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/115002200452-Cannot-programmatically-set-modified-date&quot; class=&quot;link link-external&quot;&gt;Episerver's support page &lt;em&gt;Cannot programmatically set modified date&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[S]etting the &lt;code&gt;SetChangedOnPublish&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;
and then [publishing] the page
[will] trigger an update of the modified date in the database.
So it will set the date to the same one as when you publish the page.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;setting-an-arbitrary-date&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#setting-an-arbitrary-date&quot;&gt;Setting an arbitrary date&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is more complicated
and this is what this blog post is about.&lt;/p&gt;
&lt;p&gt;First, here's the code:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Framework&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataAccess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Internal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Update the &quot;Modified&quot; datetime.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// A hacky solution that uses Epi's internal, undocumented, possibly unstable API.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Tested with EPiServer.CMS 11.14.0 and 11.19.0.&lt;/span&gt;
ContextCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ContentSaveDB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UseIChangeTrackingSavedKey&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;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&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;content &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IChangeTrackable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Saved &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PublishedAt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IChangeTrackable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SetChangedOnPublish &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's a rough explanation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use Episerver's internal &lt;code&gt;ContentSaveDB&lt;/code&gt; API
to change an internal setting.
(Or something like that –
I don't really know what's going on
since the internal API is internal and undocumented).&lt;/li&gt;
&lt;li&gt;Set the content's &lt;code&gt;Saved&lt;/code&gt; property to your desired datetime value.
(Yes, the &lt;code&gt;Saved&lt;/code&gt; property is the correct one
even though we are modifying the Modified date.
There's no &lt;code&gt;Modified&lt;/code&gt; property.)&lt;/li&gt;
&lt;li&gt;Set the content's &lt;code&gt;SetChangedOnPublish&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;.
Otherwise the new value of the &lt;code&gt;Saved&lt;/code&gt; property won't take effect.
(Yes, it's &lt;code&gt;SetChanged*&lt;/code&gt;
and not &amp;quot;&lt;code&gt;SetSaved*&lt;/code&gt;&amp;quot; which doesn't even exist.
I guess naming things is difficult.)&lt;/li&gt;
&lt;li&gt;That's it!
Now publish the content
or do whatever you were doing.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But before you go,
remember this:&lt;/p&gt;
&lt;p&gt;The code might stop working when you do any NuGet package updates.
That's because the API you are using is internal and thus unsupported.
From the
&lt;a href=&quot;https://world.optimizely.com/csclasslibraries/cms/EPiServer.DataAccess.Internal.ContentSaveDB?version=11&quot; class=&quot;link link-external&quot;&gt;&lt;code&gt;ContentSaveDB&lt;/code&gt; class's documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unsupported INTERNAL API! Not covered by semantic versioning; might change without notice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;is-this-a-good-idea&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#is-this-a-good-idea&quot;&gt;Is this a good idea?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not really,
but do you have any better ideas?&lt;/p&gt;
&lt;p&gt;In my case,
I was migrating content
from another platform (Contentful, but that's irrelevant)
to Episerver.
After I was done,
I didn't need the code anymore,
so it didn't matter
that I was using an internal, undocumented, possibly unstable API.&lt;/p&gt;
&lt;p&gt;You too shouldn't use this hacky method in any long-living code.&lt;/p&gt;
&lt;h2 id=&quot;should-this-be-even-possible&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#should-this-be-even-possible&quot;&gt;Should this be even possible?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well, that's a funny question!
According to
&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/115002200452-Cannot-programmatically-set-modified-date&quot; class=&quot;link link-external&quot;&gt;Episerver's support page &lt;em&gt;Cannot programmatically set modified date&lt;/em&gt;&lt;/a&gt;
from October 2017,
this shouldn't be possible.
From the page:&lt;/p&gt;
&lt;div data-nosnippet&gt;
&lt;blockquote&gt;
&lt;p&gt;It is &lt;strong&gt;not possible&lt;/strong&gt; to set the modified date to a specific date programmatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The date can only be changed by setting the SetChangedOnPublish property to true and then publish the page.&lt;/strong&gt;
This will in turn trigger an update of the modified date in the database.
So it will set the date to the same one as when you publish the page.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;But like I explained above,
it &lt;strong&gt;is&lt;/strong&gt; possible to set the Modified date to a specific date programmatically.&lt;/p&gt;
&lt;p&gt;(Fun fact:
Google decided to choose the misleading quote above
as a Featured snipped
(screenshot below).
Thanks Google. 😂
I have since wrapped the &lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; in a &lt;code&gt;&amp;lt;div data-nosnippet&amp;gt;&lt;/code&gt; element.)&lt;/p&gt;
&lt;p class=&quot;max-w-none&quot;&gt;&lt;img src=&quot;./google-featured-snippet.png&quot; alt=&quot;Screenshot of Google's Featured snippet from this blog post, displaying the above quote from Episerver's support page saying that it's not possible to set the modified date programmatically.&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-i-found-the-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#how-i-found-the-solution&quot;&gt;How I found the solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&amp;quot;Oh, damn,&amp;quot;
I thought to myself after reading that Episerver's support page.
But fortunately I didn't give up just yet.&lt;/p&gt;
&lt;p&gt;After googling a bit more,
I found
a &lt;a href=&quot;https://gist.github.com/kimgunnarsson/b99f041421bcfb3efa376df698e7ad35&quot; class=&quot;link link-external&quot;&gt;GitHub gist by Kim Gunnarsson&lt;/a&gt;
from April 2016.
(Funnily, the gist was created 1.5 years &lt;em&gt;before&lt;/em&gt; that Episerver's support page.)&lt;/p&gt;
&lt;p&gt;The following lines of code from the gist are relevant,
the first line being the most important:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Framework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContextCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataAccess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContentSaveDB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UseIChangeTrackingSavedKey&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;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&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 class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; clone &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CreateWritableClone&lt;/span&gt;&lt;span class=&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;
clone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Saved &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; clone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StartPublish&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
clone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SetChangedOnPublish &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The gist is currently 4.5 years old (as of October 2020)
and thus didn't work out of the box for me –
I was using &lt;code&gt;EPiServer.CMS&lt;/code&gt; version 11.14.0
and soon after version 11.19.0.
But this did work:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Framework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContextCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataAccess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Internal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContentSaveDB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UseIChangeTrackingSavedKey&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;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&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;content &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IChangeTrackable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Saved &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PublishedAt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IChangeTrackable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SetChangedOnPublish &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I.e. the &lt;code&gt;ContentSaveDB&lt;/code&gt; class has been changed into an internal class at some point.&lt;/p&gt;
&lt;p&gt;The first line can be simplified into this with proper &lt;code&gt;using&lt;/code&gt; statements:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Framework&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataAccess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Internal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ContextCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ContentSaveDB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UseIChangeTrackingSavedKey&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;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally,
you may want to slap a comment saying that this is a hacky solution.
Behold,
we ended up with the code that I already presented to you at the very beginning:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Framework&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;EPiServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataAccess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Internal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Update the &quot;Modified&quot; datetime.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// A hacky solution that uses Epi's internal, undocumented, possibly unstable API.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Tested with EPiServer.CMS 11.14.0 and 11.19.0.&lt;/span&gt;
ContextCache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Current&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ContentSaveDB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UseIChangeTrackingSavedKey&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;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&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;content &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IChangeTrackable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Saved &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PublishedAt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IChangeTrackable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SetChangedOnPublish &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hmm, did someone say this isn't possible?
Ha, checkmate!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/switch-statements-default-doesnt-have-to-be-the-last-case/</id><title>Switch statements: `default` doesn't have to be the last case</title><link href="https://mtsknn.fi/blog/switch-statements-default-doesnt-have-to-be-the-last-case/" /><published>2020-10-03T12:00:00+03:00</published><updated>2021-03-10T12:00:00+03:00</updated><category term="C#"></category><category term="Clean code"></category><category term="JavaScript"></category><category term="TypeScript"></category><content type="html">&lt;p&gt;Non-last &lt;code&gt;default&lt;/code&gt; cases are confusing
but perfectly valid.
Sometimes it makes sense to place them at the beginning or in the middle.&lt;/p&gt;
&lt;h2 id=&quot;huh-thats-possible&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#huh-thats-possible&quot;&gt;Huh, that's possible?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you think about all the &lt;code&gt;switch&lt;/code&gt; statements you have ever seen in your life,
I guess that in most of them,
the &lt;code&gt;default&lt;/code&gt; case has been the last or almost last one.&lt;/p&gt;
&lt;p&gt;I still remember how dumbfounded I was
when a friend of mine sent me
the following snippet of Unity code (C#)
that he had &lt;del&gt;copy-pasted&lt;/del&gt; picked up from a course
he was following at the time:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-cs bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;absolute -ml-6 select-none w-full sm:-ml-5&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;bg-gray-100 block border-gray-300 border-l-6 sm:border-l-4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Update&lt;/span&gt;&lt;span class=&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;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&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;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;WaitingToStart&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetKeyDown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;KeyCode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Space&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; Input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetMouseButtonDown&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;
                state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Playing&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                rb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RigidBodyType2D&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Dynamic&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;Jump&lt;/span&gt;&lt;span class=&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;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Playing&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetKeyDown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;KeyCode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Space&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; Input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetMouseButtonDown&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 function&quot;&gt;Jump&lt;/span&gt;&lt;span class=&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;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Dead&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see,
the &lt;code&gt;default&lt;/code&gt; case is at the very top.&lt;/p&gt;
&lt;p&gt;My initial thought was: dude, wtf, does this even compile?&lt;/p&gt;
&lt;p&gt;I was so used to seeing the &lt;code&gt;default&lt;/code&gt; case at the bottom
that I couldn't comprehend this.
It looked like an &lt;code&gt;if&lt;/code&gt; statement
where the &lt;code&gt;else&lt;/code&gt; branch is at the beginning.&lt;/p&gt;
&lt;p&gt;I think my inner logic circuit deduced that
since the &lt;code&gt;default&lt;/code&gt; case is the first one,
the other cases are not even checked.&lt;/p&gt;
&lt;p&gt;But turns out that's not the case
(no pun intended).
The code above is perfectly valid
and even makes sense when you think about it.
(We'll come back to this code snippet in
the &lt;a href=&quot;#what-about-the-unity-code&quot; class=&quot;link link-anchor&quot;&gt;What about the Unity code?&lt;/a&gt; section.)&lt;/p&gt;
&lt;h2 id=&quot;the-position-of-the-default-case-doesnt-matter-unless-theres-a-fallthrough&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#the-position-of-the-default-case-doesnt-matter-unless-theres-a-fallthrough&quot;&gt;The position of the &lt;code&gt;default&lt;/code&gt; case doesn't matter (unless there's a fallthrough)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After recovering from the shock of seeing that Unity code,
I had to do some digging.&lt;/p&gt;
&lt;p&gt;Like the old saying goes,
&amp;quot;all programming-related Google searches lead to Stack Overflow.&amp;quot;
Here's
&lt;a href=&quot;https://stackoverflow.com/q/3110088/1079869&quot; title=&quot;Switch statement: must default be the last case?&quot; class=&quot;link link-external&quot;&gt;the highest-voted relevant SO question&lt;/a&gt;
that I could find.
Let's see what the accepted answer by Secure says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The C99 standard is not explicit about this, but taking all facts together, it is perfectly valid.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;case&lt;/code&gt; and &lt;code&gt;default&lt;/code&gt; label are equivalent to a &lt;code&gt;goto&lt;/code&gt; label. [...]&lt;/p&gt;
&lt;p&gt;All cases are evaluated, then it jumps to the default label, if given.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(The actual answer is more thorough with excerpts from the C99 standard.)&lt;/p&gt;
&lt;p&gt;Here's what's said about
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch&quot; class=&quot;link link-external&quot;&gt;JavaScript's &lt;code&gt;switch&lt;/code&gt; statements on MDN&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;code&gt;switch&lt;/code&gt; statement first evaluates its expression.
It then looks for the first &lt;code&gt;case&lt;/code&gt; clause
whose expression evaluates to the same value as the result of the input expression
[...]&lt;/p&gt;
&lt;p&gt;If no matching &lt;code&gt;case&lt;/code&gt; clause is found,
the program looks for the optional &lt;code&gt;default&lt;/code&gt; clause
[...]
By convention, the &lt;code&gt;default&lt;/code&gt; clause is the last clause, but it does not need to be so.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One more:
here's what Paul Dixon has answered to
&lt;a href=&quot;https://stackoverflow.com/q/1241695/1079869&quot; title=&quot;default as first option in switch statement?&quot; class=&quot;link link-external&quot;&gt;a relevant SO question in the context of PHP&lt;/a&gt;
and o'boy do I agree:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is an unusual idiom,
it causes a little pause when you're reading it,
a moment of &amp;quot;huh?&amp;quot;.
It works,
but most people would probably expect to find the default case at the end.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Okay, you get the point:
the position of the &lt;code&gt;default&lt;/code&gt; case doesn't matter in
C, C#, JavaScript, PHP,
and probably many other C-style languages as well –
&lt;em&gt;if&lt;/em&gt; there are no fallthroughs.&lt;/p&gt;
&lt;p&gt;If there are fallthroughs in a &lt;code&gt;switch&lt;/code&gt; statement,
i.e. there's no &lt;code&gt;break&lt;/code&gt; or &lt;code&gt;return&lt;/code&gt; statement between some cases,
the position of the &lt;code&gt;default&lt;/code&gt; case might matter.
This is a common concept in &lt;code&gt;switch&lt;/code&gt; statements,
but if it's still confusing how they work with non-last &lt;code&gt;default&lt;/code&gt; cases,
the following code examples should clarify this.&lt;/p&gt;
&lt;h2 id=&quot;situations-where-a-non-last-default-case-can-be-useful&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#situations-where-a-non-last-default-case-can-be-useful&quot;&gt;Situations where a non-last &lt;code&gt;default&lt;/code&gt; case can be useful&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While putting the &lt;code&gt;default&lt;/code&gt; case to the end is usually the most intuitive option,
I found four situations where a non-last &lt;code&gt;default&lt;/code&gt; case can be useful.&lt;/p&gt;
&lt;p&gt;(If you can think of other useful situations,
please tell me!)&lt;/p&gt;
&lt;h3 id=&quot;cases-in-logical-order&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#cases-in-logical-order&quot;&gt;Cases in logical order&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let's say you have cases from 1 to 3,
and the default case is number 2.&lt;/p&gt;
&lt;p&gt;If you specify the cases so that the default case is the last one,
the order would be 1, 3 and 2/default.
It might instead be more intuitive to specify the cases in logical order:
1, 2/default and 3.
Like so:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-c bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo&lt;span class=&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;case&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do something...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do something...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do something...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;The more cases there are and the longer they are,
the more sense this likely makes.
On the other hand,
if the &lt;code&gt;default&lt;/code&gt; case is in the middle
of a long and complex &lt;code&gt;switch&lt;/code&gt; statement,
it might be easy to miss it.&lt;/p&gt;
&lt;p&gt;I got this idea from
&lt;a href=&quot;https://stackoverflow.com/a/3110163/1079869&quot; class=&quot;link link-external&quot;&gt;an SO answer by Salil&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;normal-case-first&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#normal-case-first&quot;&gt;Normal case first&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let's say you have a situation where there's
a normal/default case
and a bunch of error cases.&lt;/p&gt;
&lt;p&gt;If you put the normal case to the end,
it emphasizes the error cases.
Unnecessarily so,
especially if the error cases are uncommon.&lt;/p&gt;
&lt;p&gt;I got this idea from
&lt;a href=&quot;https://stackoverflow.com/a/3110336/1079869&quot; class=&quot;link link-external&quot;&gt;an SO answer by kriss&lt;/a&gt;
which included this code example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-c bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;poll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fds&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 number&quot;&gt;1000000&lt;/span&gt;&lt;span class=&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;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// here goes the normal case : some events occured&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// here goes the timeout case&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;token comment&quot;&gt;// some error occurred, you have to check errno&lt;/span&gt;
&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;kriss also talks about how the order of cases can affect performance,
but I'll just skip over this
since it smells like premature optimization.
(&lt;em&gt;Maybe&lt;/em&gt; it can be important
if you are working with
low-level, performance-critical code
and not thinking about this prematurely.)&lt;/p&gt;
&lt;h3 id=&quot;flow-control-with-fallthroughs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#flow-control-with-fallthroughs&quot;&gt;Flow control with fallthroughs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you are using a &lt;code&gt;switch&lt;/code&gt; statement for flow control
(a series of steps)
and don't break between cases,
putting &lt;code&gt;default&lt;/code&gt; to the beginning makes for a clear &lt;code&gt;switch&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;The following code example is adapted from
&lt;a href=&quot;https://stackoverflow.com/a/19301402/1079869&quot; class=&quot;link link-external&quot;&gt;an SO answer by DanielM&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-c bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; STEP_1&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do some stuff for step one&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// fallthrough&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; STEP_2&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// this follows on from step 1 or you can skip straight to it&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another good example is
&amp;quot;a state machine where an invalid state should reset the machine and proceed as though it were the initial state,&amp;quot;
from &lt;a href=&quot;https://stackoverflow.com/a/3111684/1079869&quot; class=&quot;link link-external&quot;&gt;an SO answer by supercat&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-c bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget_state&lt;span class=&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;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Fell off the rails--reset and continue */&lt;/span&gt;
    widget_state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; WIDGET_START&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* Fall through */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WIDGET_START&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WIDGET_WHATEVER&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not limited to state machines.
Take this example, adapted from
&lt;a href=&quot;https://stackoverflow.com/a/7198252/1079869&quot; class=&quot;link link-external&quot;&gt;an SO answer by Dan Larsen&lt;/a&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-c bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;color&lt;span class=&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;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No color selected so defaulting to &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Fallthrough&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; COLOR_RED&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;red&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 keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; COLOR_BLUE&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;blue&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 keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; COLOR_GREEN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;green&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 keyword&quot;&gt;break&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;color&lt;/code&gt; is red, blue or green,
the code will print
just the color.
Otherwise
(if &lt;code&gt;color&lt;/code&gt; is e.g. yellow)
the code will print
&amp;quot;No color selected so defaulting to red.&amp;quot;&lt;/p&gt;
&lt;p&gt;Though maybe it would be clearer
to move the &lt;code&gt;default&lt;/code&gt; case closer to the bottom
(unless you want to
&lt;a href=&quot;#cases-in-logical-order&quot; class=&quot;link link-anchor&quot;&gt;sort the cases in logical order&lt;/a&gt;):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-c bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;color&lt;span class=&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;case&lt;/span&gt; COLOR_BLUE&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;blue&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 keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; COLOR_GREEN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;green&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 keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No color selected so defaulting to &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Fallthrough&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; COLOR_RED&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;red&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 keyword&quot;&gt;break&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is now similar to supercat's
&amp;quot;alternative arrangement [of the state machine where] an invalid state should not reset the machine
but should be readily identifiable as an invalid state&amp;quot;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-c bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget_state&lt;span class=&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;case&lt;/span&gt; WIDGET_IDLE&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    widget_ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;widget_hardware_off&lt;/span&gt;&lt;span class=&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;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WIDGET_START&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WIDGET_WHATEVER&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    widget_state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; WIDGET_INVALID_STATE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* Fall through */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WIDGET_INVALID_STATE&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    widget_ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;widget_hardware_off&lt;/span&gt;&lt;span class=&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;// ... do whatever else is necessary to establish a &quot;safe&quot; condition&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;preventing-accidental-fallthroughs-to-the-default-case&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#preventing-accidental-fallthroughs-to-the-default-case&quot;&gt;Preventing accidental fallthroughs to the &lt;code&gt;default&lt;/code&gt; case&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If the &lt;code&gt;default&lt;/code&gt; case is the first one,
it's impossible for other cases
to accidentally fall through to the &lt;code&gt;default&lt;/code&gt; case.&lt;/p&gt;
&lt;p&gt;This idea is from
&lt;a href=&quot;https://stackoverflow.com/a/18470387/1079869&quot; class=&quot;link link-external&quot;&gt;an SO answer by JaredPar&lt;/a&gt;.
He continues to clarify:
&amp;quot;This means &lt;code&gt;default&lt;/code&gt; will run if, and only if,
the value matches no &lt;code&gt;case&lt;/code&gt; statements in the &lt;code&gt;switch&lt;/code&gt; block.&amp;quot;&lt;/p&gt;
&lt;p&gt;Using a linter would also help you
catch accidental fallthroughs,
so I don't know whether the confusion
caused by placing the &lt;code&gt;default&lt;/code&gt; case to the top
outweighs the benefits.
(To be fair, JaredPar also writes:
&amp;quot;Note I'm not saying I agree with it,
this is simply the logic others have presented to me in the past.&amp;quot;)&lt;/p&gt;
&lt;h2 id=&quot;so-should-you-use-non-last-default-cases&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#so-should-you-use-non-last-default-cases&quot;&gt;So, should you use non-last &lt;code&gt;default&lt;/code&gt; cases?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unless you have a good reason to do otherwise,
it's safest to put the &lt;code&gt;default&lt;/code&gt; case to the end.
This way anyone familiar with &lt;code&gt;switch&lt;/code&gt; statements
can more easily understand the structure of your &lt;code&gt;switch&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;But if you have a good reason,
go ahead.
Just be prepared that your code might be initially rather confusing to other developers.&lt;/p&gt;
&lt;h2 id=&quot;what-about-the-unity-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#what-about-the-unity-code&quot;&gt;What about the Unity code?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I would put the mindboggling code sent to me by my friend to the
&lt;a href=&quot;#cases-in-logical-order&quot; class=&quot;link link-anchor&quot;&gt;Cases in logical order&lt;/a&gt; category.
It also somewhat belongs to the
&lt;a href=&quot;#flow-control-with-fallthroughs&quot; class=&quot;link link-anchor&quot;&gt;Flow control with fallthroughs&lt;/a&gt; category.&lt;/p&gt;
&lt;p&gt;After some thought,
it's actually logical to present the game states (&lt;code&gt;switch&lt;/code&gt; cases)
in the order they have been presented:
&amp;quot;waiting to start,&amp;quot; &amp;quot;playing&amp;quot; and &amp;quot;dead.&amp;quot;
That's the natural flow of the game states.
The initial game state is &amp;quot;waiting to start,&amp;quot;
so the most logical position for the &lt;code&gt;default&lt;/code&gt; case is at the beginning.&lt;/p&gt;
&lt;p&gt;In the end,
the code was actually quite clever!&lt;/p&gt;
</content></entry><entry><id>https://mtsknn.fi/blog/how-to-remember-markdowns-link-syntax/</id><title>Mnemonic for Markdown's link syntax (and image syntax)</title><link href="https://mtsknn.fi/blog/how-to-remember-markdowns-link-syntax/" /><published>2020-09-28T12:00:00+03:00</published><updated>2022-04-25T12:00:00+03:00</updated><category term="Markdown"></category><category term="Mnemonics"></category><content type="html">&lt;p&gt;Was it &lt;code&gt;[text](url)&lt;/code&gt; or &lt;code&gt;(text)[url]&lt;/code&gt;?
Use this one weird trick to remember –
Markdown consultants HATE it!
Spoiler: it's the former since it looks like a function call.&lt;/p&gt;
&lt;h2 id=&quot;link-syntax-looks-like-a-function-call&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#link-syntax-looks-like-a-function-call&quot;&gt;Link syntax looks like a function call&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first part looks like an array of words:
&lt;code&gt;[link text]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second part looks like it's used to call a function with one parameter:
&lt;code&gt;(url)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Put together:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;I'm an array of words&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;/and-im-a-parameter-to-a-function-call&lt;/span&gt;)&lt;/span&gt;

&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;Link text with &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;bold words&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 url&quot;&gt;https://example.com/&lt;/span&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;optional-second-parameter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#optional-second-parameter&quot;&gt;Optional second parameter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thinking of functions,
you can also provide a title as the second parameter.
These are all valid and identical
(according to the &lt;a href=&quot;https://spec.commonmark.org/0.30/&quot; class=&quot;link link-external&quot;&gt;CommonMark Spec&lt;/a&gt;):&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;Link text&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;/some-url&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;And a title&quot;&lt;/span&gt;)&lt;/span&gt;
[Link text](/some-url 'And a title')
[Link text](/some-url (And a title))
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output (×3):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/some-url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&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;And a title&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;Link text&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;title&lt;/code&gt; attribute is not very accessible,
so you shouldn't rely on it too much.&lt;/p&gt;
&lt;h3 id=&quot;anti-mnemonic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#anti-mnemonic&quot;&gt;Anti-mnemonic&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;(link text)[url]&lt;/code&gt; would look like you are using the &lt;code&gt;url&lt;/code&gt; key
to access a value from... hmm, from the expression &lt;code&gt;(link text)&lt;/code&gt;,
which isn't even a valid expression?
That wouldn't make as much sense.&lt;/p&gt;
&lt;h2 id=&quot;alternative-link-syntaxes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#alternative-link-syntaxes&quot;&gt;Alternative link syntaxes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For completeness,
let's see other ways of specifying links in Markdown.
Reference links are also related to Markdown's image syntax.&lt;/p&gt;
&lt;h3 id=&quot;autolinks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#autolinks&quot;&gt;Autolinks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are simple:
wrap an absolute URI or an email address in angle brackets.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&amp;lt;https://example.com/foo/bar&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;mail@example.com&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com/foo/bar&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;https://example.com/foo/bar&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mailto:mail@example.com&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;mail@example.com&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;reference-links&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#reference-links&quot;&gt;Reference links&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A reference link consists of link text and a link label.&lt;/p&gt;
&lt;p&gt;The link label should have a corresponding &amp;quot;link reference definition&amp;quot; somewhere in the document,
for example at the end of a section or at the end of the whole document.
Link labels are case-insensitive.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Check out &lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;foo&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;1&lt;/span&gt;]&lt;/span&gt;, &lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;bar&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;2&lt;/span&gt;]&lt;/span&gt; and &lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;baz&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;3&lt;/span&gt;]&lt;/span&gt;.

&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&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; https://example.com/foo&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&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; https://example.com/bar&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://example.com/baz&lt;/span&gt;

Do you know what's &lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;my favorite search engine&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;duck&lt;/span&gt;]&lt;/span&gt;?
I like it more than &lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;Microsoft's search engine&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;bing&lt;/span&gt;]&lt;/span&gt;.

&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;duck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://duck.com/&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;bing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://bing.com/&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;!-- prettier-ignore --&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Check out
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com/foo&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;foo&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;,
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com/bar&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;bar&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; and
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com/baz&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;baz&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;.

Do you know what's &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://duck.com/&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;my favorite search engine&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;?
I like it more than &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://bing.com/&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;Microsoft's search engine&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Collapsed reference links&lt;/h4&gt;
&lt;p&gt;If the link text and label are the same
(labels are case-insensitive),
you can use &amp;quot;collapsed reference links&amp;quot; and drop the label:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Check out [foo][], [Bar][] and [BAZ &amp;amp; qux][].

&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://example.com/foo&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://example.com/bar&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;baz &amp;amp; qux&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://example.com/baz&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Shortcut reference links&lt;/h4&gt;
&lt;p&gt;&amp;quot;Shortcut reference links&amp;quot; take a step further by allowing you to drop the empty brackets as well:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;Check out [foo], [Bar] and [BAZ &amp;amp; qux].

&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://example.com/foo&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://example.com/bar&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;baz &amp;amp; qux&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https://example.com/baz&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;image-syntax-link-syntax&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#image-syntax-link-syntax&quot;&gt;Image syntax = &lt;code&gt;!&lt;/code&gt; + link syntax&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The image syntax is the same as the link syntax,
except that there's a bang (&lt;code&gt;!&lt;/code&gt;) at the beginning,
and the link text is the image's alt text:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;A nice pic&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;/image-url&lt;/span&gt;)&lt;/span&gt;
&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;A nice pic&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;a nice pic&lt;/span&gt;]&lt;/span&gt;
![A nice pic][]
![A nice pic]

&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a nice pic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /image-url&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output (×4):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;/image-url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;A nice pic&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Omitting the alt text produces &lt;code&gt;alt=&amp;quot;&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;![](/image-url)
![][a nice pic]

&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a nice pic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /image-url&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output (×2):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;/image-url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;image-link&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#image-link&quot;&gt;Image link&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Nothing special; just the same link syntax where the link text is an image:&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-md bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&quot;&gt;&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;![A nice pic&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;/image-url&lt;/span&gt;)&lt;/span&gt;](/link-url)
&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;![A nice pic&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;a nice pic&lt;/span&gt;]&lt;/span&gt;](/link-url)
[![A nice pic][]](/link-url)
[![A nice pic]](/link-url)

&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;![A nice pic&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;/image-url&lt;/span&gt;)&lt;/span&gt;][some page]
&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;![A nice pic&lt;/span&gt;][&lt;span class=&quot;token variable&quot;&gt;a nice pic&lt;/span&gt;]&lt;/span&gt;][some page]
[![A nice pic][]][some page]
[![A nice pic]][some page]

&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a nice pic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /image-url&lt;/span&gt;
&lt;span class=&quot;token url-reference url&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;some page&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /link-url&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Huh, quite busy syntax.&lt;/p&gt;
&lt;p&gt;Output (×8):&lt;/p&gt;
&lt;pre aria-label=&quot;Code block&quot; class=&quot;language-html bg-white border-t border-b max-w-none -mx-6 my-4 relative sm:border sm:mx-0 sm:rounded-md&quot; role=&quot;region&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;min-w-full !px-6 !py-4 relative sm:!px-5&quot;&gt;&lt;span class=&quot;actual-code inline-block -ml-6 pl-6 relative sm:-ml-5 sm:pl-5&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;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/link-url&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;/image-url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;A nice pic&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;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;further-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;link link-anchor&quot; href=&quot;#further-resources&quot;&gt;Further resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://spec.commonmark.org/0.30/&quot; class=&quot;link link-external&quot;&gt;CommonMark Spec&lt;/a&gt; has more examples and edge cases covered.
Check out these sections of the spec:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://spec.commonmark.org/0.30/#links&quot; class=&quot;link link-external&quot;&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spec.commonmark.org/0.30/#autolinks&quot; class=&quot;link link-external&quot;&gt;Autolinks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spec.commonmark.org/0.30/#reference-link&quot; class=&quot;link link-external&quot;&gt;Reference links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spec.commonmark.org/0.30/#images&quot; class=&quot;link link-external&quot;&gt;Images&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content></entry></feed>