<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Tris Sherliker</title>
  <subtitle>IP, technology &amp;#x26; commercial law</subtitle>
  <link href="https://tris.sherliker.net/feed.xml" rel="self"/>
  <link href="https://tris.sherliker.net"/>
  <updated>2026-07-04T00:00:00Z</updated>
  <id>https://tris.sherliker.net</id>
  <author>
    <name>Tris Sherliker</name>
    <email>tris@sherliker.net</email>
  </author>
  
  <entry>
    <title>Red Lines</title>
    <link href="https://tris.sherliker.net/blog/red-lines/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2025-11-02T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/red-lines/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;I had a negotiation&lt;/span&gt; a while ago which very nearly derailed itself. I keep thinking back to what happened and what it tells me as a lawyer and a person. As lawyers, we’re usually advocating other people’s views. Our business is representing other people’s business, but sometimes it can be hard to keep track.&lt;/p&gt;
&lt;p&gt;This was the settlement stage of a long-running dispute. The contract had gone back and forth several times, resulting in layered redline.&lt;label for=&quot;md-however-a-case&quot; class=&quot;margin-toggle &quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;md-however-a-case&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;However a case begins, almost all of them end with drafting tweaks on an A4-shaped MSWord document trying to untangle the redline.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;Redline-swapping&lt;/span&gt; is a nightmare if you don’t keep good track of your versioning, because it all blends together unless you take time to check the metadata for each revision. Worse, most law firms automatically strip out the metadata of all sent attachments out of caution, so it becomes verbal soup.&lt;label for=&quot;md-version-control-was&quot; class=&quot;margin-toggle &quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;md-version-control-was&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Version control was solved in software decades ago but it’s harder in law because (a) most lawyers are allergic to plain text and (b) it’s much, much easier to version collaboratively than it is when you’re adversarial.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;In this case,&lt;/span&gt; we thought we were at the end. We’d decided to accept some of the less reasonable requests from the other side just to get the deal done, so we expected to be getting a signature back quickly. Couldn’t work out why it took so long to hear back. After chasing, we got another tangled version of the agreement, with comments this time:&lt;/p&gt;
&lt;p&gt;The guy on the other side had clearly taken against some of the wording and committed &lt;em&gt;several paragraphs&lt;/em&gt; in the margin to explain why it was blocking the deal, how unreasonable it was, and what awful people we were for having it in the draft in the first place.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;A quick phonecall&lt;/span&gt; was enough to remind him that the wording came from his client, and we agreed with him. The deal was done within the day.&lt;/p&gt;
&lt;/section&gt;</content>
  </entry>
  
  <entry>
    <title>Putting scripts into $PATH</title>
    <link href="https://tris.sherliker.net/blog/putting-scripts-into-dollarpath/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-03-22T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/putting-scripts-into-dollarpath/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;Whenever I find myself doing a task for a third&lt;/span&gt; time, it’s probably going to come up again and probably worth writing a script to get it done faster when it does. This is a pretty common habit far from unique, but mine were beginning to get out of hand so I was interested to see &lt;a href=&quot;https://evanhahn.com/why-alias-is-my-last-resort-for-aliases/&quot;&gt;Evan Hahn’s post&lt;/a&gt; about handling the cutter.&lt;/p&gt;&lt;h3 id=&quot;ditching-aliases&quot;&gt;Ditching aliases&lt;/h3&gt;&lt;p&gt;Instead of using aliases in &lt;code&gt;bashrc&lt;/code&gt; (or in my case usually &lt;code&gt;config.fish&lt;/code&gt;) for execution, Evan recommends adding basic scripts to a directory. You can then put that directory in your PATH &lt;label for=&quot;sd-the-usdpath-is-the&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-the-usdpath-is-the&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;The $PATH is the list of places where your system looks to find commands it’s being executed. This is different to the common (lowercase) “file path” showing where a file is found.&lt;/span&gt; and have the script execute right from your shell, while the directory is version controlled. &lt;/p&gt;&lt;p&gt;The effect is like a personal multitool that’s ready whenever you need it. Maybe obvious in hindsight but quite powerful in practice. &lt;a href=&quot;https://jvns.ca/blog/2025/02/13/how-to-add-a-directory-to-your-path/&quot;&gt;Julia Evans also explains&lt;/a&gt; how to do this in a very clear way, covering lots of different cases.&lt;/p&gt;&lt;p&gt;I found the idea compelling and started using it straight away.&lt;/p&gt;&lt;h3 id=&quot;doing-the-thing&quot;&gt;Doing the thing&lt;/h3&gt;&lt;p&gt;I use fish shell (because it &lt;a href=&quot;https://shkspr.mobi/blog/2021/06/what-do-you-call-open-source-software-that-just-works/&quot;&gt;just works&lt;/a&gt;), so I can use the handy “do what you mean” built-in&lt;label for=&quot;sd-although-julia-evans&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-although-julia-evans&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Although Julia Evans &lt;a href=&quot;https://jvns.ca/blog/2025/02/13/how-to-add-a-directory-to-your-path/#a-note-on-fish-add-path&quot;&gt;warns against this&lt;/a&gt; for a couple of reasons, including that it’s hard to undo.&lt;/span&gt; to do this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;~&gt; fish_add_path (realpath ./script-path)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The (realpath …) function in the snippet above will be replaced by the full directory path. That will then be added to the PATH.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;symlinks-is-always-the-answer&quot;&gt;“Symlinks” is always the answer&lt;/h2&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;One tweak&lt;/span&gt; to the setup I use is to have two folders:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/.../scripts&lt;/code&gt; for the scripts themselves, which is version controlled and&lt;/li&gt;
&lt;li&gt;a subdirectory &lt;code&gt;/.../scripts/script-path&lt;/code&gt;, which goes into the PATH.&lt;/li&gt;
&lt;/ul&gt;&lt;figure class=&quot;marginfigure&quot;&gt; &lt;label for=&quot;mf-tree&quot; class=&quot;margin-toggle&quot;&gt;⊕&lt;/label&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;mf-tree&quot; class=&quot;margin-toggle&quot; /&gt;
&lt;span class=&quot;marginnote&quot;&gt;
&lt;code&gt;scripts/&lt;br /&gt;├── myscript.sh&lt;br /&gt;├── .gitignore&lt;br /&gt;└── script-path/&lt;br /&gt;    └── myscript&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;
&lt;code&gt;script-path/&lt;/code&gt; is gitignored and goes on $PATH; the scripts themselves stay under version control in the parent directory.
&lt;/span&gt;&lt;/figure&gt;&lt;p&gt;I can then use git to track the version control in the &lt;code&gt;scripts&lt;/code&gt; directory, without needing to have a git history in my PATH (which feels like it could go wrong). So:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;/.../scripts ~&gt; mkdir script-path
/.../scripts ~&gt; git init
/.../scripts ~&gt; echo &quot;script-path/&quot; &gt;&gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All that remains is to add the scripts themselves to the subdirectory. Rather than making copies of the various scripts, symlinks do the job cleanly. This way even when I update the main files, the symlinks still point where I want them to, and the files themselves remain under version control. Add scripts one at a time&lt;label for=&quot;sd-the-first-time-i-did&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-the-first-time-i-did&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;The first time, I did it in bulk. All my existing scripts were named with a .sh extension so in fish: &lt;code&gt;~&gt; for sh_file in *.sh; set filename_without_extension (string split -r -m1 . $sh_file); ln -s (realpath $sh_file) ./script-path/$filename_without_extension; end&lt;/code&gt;&lt;/span&gt; with:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;ln -s (realpath ./scripts/myscript.sh) ./script-path/myscript
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And don’t forget to give all the script files executable permission with &lt;code&gt;chmod +x filename.sh&lt;/code&gt;.&lt;/p&gt;&lt;/section&gt;
</content>
  </entry>
  
  <entry>
    <title>When was a webpage modified?</title>
    <link href="https://tris.sherliker.net/blog/when-was-a-webpage-modified/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-05-02T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/when-was-a-webpage-modified/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;Working out the date&lt;/span&gt; of a web page can be useful (especially for prior art in patent cases, and for evidence in litigation), but it can also be difficult. Most of the time a useful page has a date on it of some kind which may be reliable. For others the &lt;a href=&quot;https://archive.org/&quot;&gt;Wayback Machine&lt;/a&gt; helps perhaps about half the time but it hasn’t got perfect coverage. There’s another tool that can sometimes&lt;label for=&quot;sd-this-is-mainly&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-this-is-mainly&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;This is mainly directed to static web content, i.e. content stored as files on a server. A lot of web content is generated dynamically and isn’t stored as files in the same way.&lt;/span&gt; help fill the gap.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;the-last-modified-header&quot;&gt;The Last-Modified header&lt;/h2&gt;&lt;p&gt;When you save or edit a file on your computer, the system logs a “last modified” timestamp recording the change. This is also true for a lot of web content. &lt;/p&gt;&lt;p&gt;When your browser requests a page online, it sends an HTTP &lt;code&gt;request&lt;/code&gt; and the server’s response includes a set of HTTP &lt;code&gt;headers&lt;/code&gt;, with extra information alongside the web content itself. This often includes a &lt;code&gt;Last-Modified&lt;/code&gt; header, a time and date stamp recording when the content was last changed on the server. The &lt;code&gt;Last-Modified&lt;/code&gt; header is used by web systems to detect whether something has changed since it was last fetched (e.g. for caching and archiving), but it is useful evidence of modification or publication date. &lt;/p&gt;&lt;p&gt;A response containing one looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Last-Modified: Tue, 15 Oct 2024 09:32:00 GMT
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It isn’t always reliable and there are lots of reasons that a webpage’s date might show as more recent than it in fact is. Some servers set it accurately, others might be generating content dynamically at the server and set it to the current date and time; or it might record the last time the server’s cache was refreshed. But it’s a useful point of information, and usually broadly reliable in the same way as other computer timestamp information.&lt;/p&gt;&lt;h3 id=&quot;checking-for-last-modified-timestamps&quot;&gt;Checking for Last-Modified Timestamps&lt;/h3&gt;&lt;p&gt;To view in Chrome: &lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Go the web page you’re interested in.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;F12&lt;/code&gt;, opening the developer tools console. This allows viewing the normally-hidden metadata.&lt;/li&gt;
&lt;li&gt;Choose the “Network” tab in the console. &lt;/li&gt;
&lt;li&gt;Refresh the page (pressing &lt;code&gt;F5&lt;/code&gt;), so the console can record the request and response traffic.&lt;/li&gt;
&lt;li&gt;There will often be several files loaded (the web page itself; images; scripts etc): click on the one you’re interested in.&lt;/li&gt;
&lt;li&gt;Look for the &lt;code&gt;Last-Modified&lt;/code&gt; header. &lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Here’s an example for &lt;a href=&quot;http://landley.net/history/mirror/collate/aa080499b.htm&quot;&gt;http://landley.net/history/mirror/collate/aa080499b.htm&lt;/a&gt;, which shows that the page was &lt;code&gt;last-modified Tue, 28 May 2002 18:51:09 GMT&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/lastmod-0.png&quot; alt=&quot;metadata screenshot&quot; /&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;the-wayback-machine&quot;&gt;The Wayback Machine&lt;/h2&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;When the Internet Archive’s Wayback Machine&lt;/span&gt; snapshots pages it also preserves the HTTP headers that it saw at the time (i.e. those which accompanied the original response to the Archive, at the time when it retrieved the page in question). This is labelled with &lt;code&gt;X-Archive-Orig-&lt;/code&gt; or &lt;code&gt;X-Orig-&lt;/code&gt; prefix for example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;X-Archive-Orig-Last-Modified: Tue, 15 Oct 2024 09:32:00 GMT
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To find these, load the archived version of the page on &lt;code&gt;web.archive.org&lt;/code&gt;, then open DevTools and inspect the response headers as above. Look for any header beginning &lt;code&gt;X-Archive-Orig-&lt;/code&gt;. This can help to establish a sequence of edits (or that there were no edits) between snapshot date and the present.&lt;/p&gt;&lt;/section&gt;
</content>
  </entry>
  
  <entry>
    <title>Vibecoding a simple feature with Claude</title>
    <link href="https://tris.sherliker.net/blog/vibecoding-a-simple-feature-with-claude/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-05-09T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/vibecoding-a-simple-feature-with-claude/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;My side project&lt;/span&gt; has been entirely handcoded in the backend, until today. I’ve used Claude Code a great deal for frontend work — I am no web designer — but I’ve tended my backend carefully with my own hands.&lt;label for=&quot;sd-in-fact-using-my&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-in-fact-using-my&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;In fact using my hands is part of the point, being effective rehab while recovering from an injury.&lt;/span&gt; Today I decided to break that habit and try adding a feature using Claude to generate all the code edits.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://buntool.co.uk/&quot;&gt;BunTool&lt;/a&gt; (&lt;a href=&quot;https://github.com/TrisSherliker/buntool-website-git&quot;&gt;git&lt;/a&gt;) is for making PDF bundles for use in court and legal settings, and one feature requested by a colleague (who absolutely knows what she is talking about and should be listened to) was the ability to add a custom coversheet. That’s a great test case, because the feature is easy to conceptualise and express, it touches multiple points in the bundle-making pipeline from frontend to output, and because I can hold the logic in my head from beginning to end for checking purposes.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;framework&quot;&gt;Framework&lt;/h2&gt;&lt;p&gt;Also a good chance to test a new (to me) &lt;code&gt;claude.md&lt;/code&gt; variant. I heard from a friend today that &lt;a href=&quot;https://github.com/forrestchang/andrej-karpathy-skills&quot;&gt;Forrest Chang’s Karpathy-Inspired Claude Code Guidelines&lt;/a&gt; was useful&lt;label for=&quot;sd-described-as-less&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-described-as-less&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Described as &lt;em&gt;“A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy’s observations on LLM coding pitfalls.”&lt;/em&gt; I’ve used Claude enough in the past that I think I’ll be able to spot differences, though this is a slightly different exercise.&lt;/span&gt;, so I installed it as a plugin before I got started. This was pretty easy using claude’s inline plugin management commands.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;specifying&quot;&gt;Specifying&lt;/h2&gt;&lt;p&gt;I decided to work from a markdown checklist and iterate through the steps one by one, so I started by planning out my spec for the feature: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;# Adding coversheet checklist

## Backend

- [ ] buntoolconfig.js - add bool option
- [ ] validate cover page function: check file = 1 page or extract first page, return first page
- [ ] Add validation call in buntoolMain.js
- [ ] at 3/11 in buntoolMain.js Creation of TOC entries, page numbers +1 if coversheet
- [ ] at 5/11 buntoolMain.js (generating TOC pages) page number needs to respect toc entries setting if coversheet present (just check carries through)
- [ ] After current step 7/11 buntoolMain.js (add new step before current step 8, after toc is merged), the result of the step7 merge should then be merged again with coversheet
- [ ] the abbreviated justtheeindex flow in buntoolMain.js should merge with coversheet


## frontend

- [ ] Button to add optional coversheet
- [ ] call validate function at point of upload (belt and braces)
- [ ] show selected filename
- [ ] clear/remove button
- [ ] error handling for invalid file
- [ ] submit logic to accommodate coversheet as parameter coversheetFile
- [ ] add mention in tutorial
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is spec’d by reference to the logic flow in my &lt;code&gt;buntoolMain.js&lt;/code&gt; main logic flow, but those steps in turn call out to various submodules.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;step-by-step&quot;&gt;Step by step&lt;/h2&gt;&lt;p&gt;Setting Claude to ask-before-edits gave me peace of mind, and then I prompted it to follow stepwise (&quot;&lt;em&gt;ok let’s do the coversheet adding plan step by step. start with step 1: show me your proposed edits&lt;/em&gt;&quot;). Baby steps from the interface within VSCode:&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/claude-polite.png&quot; alt=&quot;Claude politely making edits without fluff&quot; /&gt;&lt;figcaption&gt;Claude politely making edits without fluff&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;And so it proceeded.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;Overall it went very well.&lt;/span&gt; There were a few nits and irritations though:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Claude often used variable names which were fine in isolation but which were confusing in their overall context. For example &lt;code&gt;coversheetFile&lt;/code&gt; and &lt;code&gt;coversheetPDF&lt;/code&gt; were two different but closely connected things, one derived from the other, both the same type. I much preferred names that conveyed the functions - &lt;code&gt;coversheetFile&lt;/code&gt; and &lt;code&gt;validatedCoversheet&lt;/code&gt;. It would have been annoying to come back to maintain the confusing variables in future. &lt;/li&gt;
&lt;li&gt;Without Forrest Chang’s plugin, Claude just loved haphazardly deleting my comments. I’m sure that some people would do the same, but I put them there for a reason! I found the plugin helped with this, suppressing unwanted edits.&lt;/li&gt;
&lt;li&gt;Although it had no respect for my comments, it seemed to find the logging prints unassailable. They count up stepwise in the main pipeline (&quot;step 4/11&quot; etc), so a &lt;code&gt;sed&lt;/code&gt; call or two was needed to update them globally as new pipeline steps were added.&lt;label for=&quot;sd-using-less-than-code&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-using-less-than-code&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Using &lt;code&gt;sed&lt;/code&gt; is quite boring. Luckily Claude could also save me all the typing.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;In some cases it got the logical flow of steps out of order. That’s fine, this is why I monitor and could correct it. Somewhat sassily it reacted to that by amending my spec to hyperclarify… even after the edit was finished!&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;So I ended up being quite hands-on and I couldn’t surrender control entirely. Having said that, if I weren’t using Claude for maintaining my own stuff a lot of this wouldn’t matter a jot.&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/claude-check.png&quot; alt=&quot;I let the LLM have the satisfaction of checking things off its list, and it took the opportunity for some sassy backchat.&quot; /&gt;&lt;figcaption&gt;I let the LLM have the satisfaction of checking things off its list, and it took the opportunity for some sassy backchat.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;At one point while testing&lt;/span&gt; I found quite a subtle bug with hyperlinking, which took a while to solve because it seemed to be only intermittently reproducible&lt;label for=&quot;sd-a-sort-of-less-than&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-a-sort-of-less-than&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;a sort of &lt;a href=&quot;https://en.wikipedia.org/wiki/Heisenbug&quot;&gt;Heisenbug&lt;/a&gt;, since trying to debug it with my preferred PDF viewers (which give richer control than a browser viewer) led to a different experience.&lt;/span&gt;. This was very annoying but I eventually worked out that it was due to relying on undefined behaviour being handled in a certain way. This wasn’t Claude’s fault, but Claude confidently proposed a fix that broke things much more acutely. I fixed it by hand in the end.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;overall&quot;&gt;Overall?&lt;/h2&gt;&lt;p&gt;But I didn’t get the most out of it because I’m apparently very stuffy about edits to my own handcoded work. It wasn’t quite as smooth as I hoped, but that was partly because I was so opinionated about how things should look that I tended to want to micromanage the result anyway. &lt;/p&gt;&lt;p&gt;In the frontend I’m perfectly happy to deploy UI features via Claude, and I went on to depend on it for an autosave feature which worked entirely in frontend. I suppose the different level of caution is appropriate. &lt;/p&gt;&lt;/section&gt;
</content>
  </entry>
  
  <entry>
    <title>Cloudflare cache frustration</title>
    <link href="https://tris.sherliker.net/blog/cloudflare-cache-frustration/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-05-10T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/cloudflare-cache-frustration/</id>
    <content type="html">&lt;section&gt;&lt;div class=&quot;epigraph&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;
&lt;footer&gt;Phil Karlton&lt;/footer&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;I spent most of today&lt;/span&gt; debugging a senseless
error.&lt;/p&gt;
&lt;p&gt;This morning’s flight of BunTool emails included a suggestion to include
compatibility for Times New Roman and Arial fonts. That’s a great idea because
some tribunals specify font types&lt;label for=&quot;sd-in-fact-it-s-a-minor&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-in-fact-it-s-a-minor&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;In fact it’s a minor access to justice issue that courts require
people to use proprietary fonts, but probably not a deliberate one. Most people
seem to think of TNR and Arial as being generic and free, even if that’s wrong.
Fair enough given their prevalence and the hyper-niche nuance of font IP law.&lt;/span&gt; and the plumbing for it was mostly
there in the backend.&lt;/p&gt;
&lt;p&gt;The trouble is that both those fonts are proprietary and BunTool is FOSS. So I
found two excellent alternatives - respectively, &lt;a href=&quot;https://software.sil.org/charis/&quot;&gt;CharisSIL&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Liberation_fonts&quot;&gt;Liberation Sans&lt;/a&gt;.&lt;label for=&quot;sd-why-not-liberation&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-why-not-liberation&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Why not Liberation Serif too? Only because I liked Charis. All the
Liberation fonts are great!&lt;/span&gt; So I loaded those in and connected up the plumbing, spun up the test cases and all worked well. &lt;/p&gt;
&lt;p&gt;Deploying broke everything. Cloudflare was serving some fonts but not others,
even fonts of the same size and in the same directories as working fonts. &lt;/p&gt;
&lt;p&gt;Why? After two hours I’m pretty sure it was a
Cloudflare caching error. Branching and deploying to a fresh preview instance confirmed this was probably the error, since it didn’t have the same problems. But annoyingly even purging CF’s cache didn’t fix it. &lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;In the end&lt;/span&gt; I did: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Roll back to working instance&lt;/li&gt;
&lt;li&gt;Copy font files only (and no code) from my &lt;code&gt;dev&lt;/code&gt; branch to &lt;code&gt;main&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;redeploy&lt;/li&gt;
&lt;li&gt;then merge &lt;code&gt;dev&lt;/code&gt; into &lt;code&gt;main&lt;/code&gt;, once fonts were already deployed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Somehow, that stage of copying just the fonts dir into CF’s deployment first,
and then merging seemed to have helped. Or perhaps it just caught up over the
two hours that I was trying to diagnose the problem? I’ll never know.&lt;/p&gt;
&lt;/section&gt;</content>
  </entry>
  
  <entry>
    <title>What logs does BunTool save?</title>
    <link href="https://tris.sherliker.net/blog/what-logs-does-buntool-save/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-05-24T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/what-logs-does-buntool-save/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;I say on its Privacy page and homepage that &lt;a href=&quot;https://buntool.co.uk/&quot;&gt;BunTool&lt;/a&gt; doesn’t log any personal information. This is part of the point, because it’s a private tool and if it ingested information about everyone and their legal cases it would be worthless&lt;/p&gt;
&lt;p&gt;There is &lt;em&gt;some&lt;/em&gt; logging though, and I recently posted about this on LinkedIn: &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/buntool-logs.png&quot; alt=&quot;LinkedIn post&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As you see, it’s technical logging only without any personal info. Having posted that I realised people might like to know exactly what is logged, so here are some examples of some real-life logs from the last few days, chosen at random (and slightly prettified for ease of display in a news post):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;6114&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;6022&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;6023&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Started&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2026–05–21 22:08:22&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2026–05–21 11:06:56&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2026–05–21 11:12:04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files used&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;11&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page count&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;59&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;159&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;119&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.1 MB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;88.9 MB&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;0.7 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duration&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.3 s&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;4.8 s&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;Interrupted: cancelled by user&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;OK&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That’s about it. The error codes (here labelled &quot;Status&quot;) can vary - for example there was an increasing trend of errors where people were creating larger and larger bundles which showed up as &lt;code&gt;realloc error (8765432 bytes failed)&lt;/code&gt; and reference a line of the code where the problem arose&lt;label for=&quot;sd-the-stack-trace&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-the-stack-trace&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;The “stack trace”&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;But still, no personal information.&lt;/p&gt;
&lt;/section&gt;</content>
  </entry>
  
  <entry>
    <title>Ah whoops. Computers can have accidents now</title>
    <link href="https://tris.sherliker.net/blog/ah-whoops.-computers-can-have-accidents-now/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-05-30T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/ah-whoops.-computers-can-have-accidents-now/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;I was using Claude to set up dotfile syncing before provisioning a new machine, and during the session I got this: &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/2026-05-30-computer-accidents.png&quot; alt=&quot;Whoops, nothing to see here&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&gt; Updated plan
User rejected Claude&#39;s plan:
Plan: Exit accidental plan mode

Plan mode was triggered accidentally mid-conversation. 
No implementation task is being planned. Simply exit plan 
mode and continue the planning session with the user.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a very human sort of “accident”. The idea of software doing something relatably and accidentally in 2026 is pretty striking. A few years ago this would have been fiction. &lt;/p&gt;
&lt;/section&gt;</content>
  </entry>
  
  <entry>
    <title>Vulnerability reports are still special</title>
    <link href="https://tris.sherliker.net/blog/vulnerability-reports-are-still-special/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-06-24T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/vulnerability-reports-are-still-special/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;I’ve just been reading Filippo Valsorda’s well-written post about why, in the age of LLMs and automated security analysis, &lt;a href=&quot;https://words.filippo.io/vuln-reports/&quot;&gt;Vulnerability Reports are not Special Anymore&lt;/a&gt;. It’s worth reading, and he also added to it to address several comments. &lt;/p&gt;&lt;p&gt;But I think I disagree with his premise. To my mind, vulnerability reports &lt;em&gt;are&lt;/em&gt; still special and the fact that they are more accessible to a wider range of people fuzzing software through LLMs doesn’t change this, even in the open source world. &lt;/p&gt;&lt;p&gt;To be clear, I don’t claim to know better than Filippo: he is immersed in that world! I’m a lawyer who handles security through a very different lens, so I am only dealing with this from a high level, damage-limitation-after-the-event sort of perspective. I also don’t want to downplay how serious it can be to suffer the information overload of AI-generated materials coming thick and fast but taking disproportionate time to verify.&lt;label for=&quot;sd-but-dealing-with&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-but-dealing-with&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;But dealing with hard-to-verify overload is a problem where I think lawyers and software engineers do have a similar experience.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Anyway with those caveats, I had the reaction I had for three reasons: &lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;1-knowledge-is-power&quot;&gt;1: Knowledge is power&lt;/h2&gt;&lt;p&gt;Knowledge is not always power, but knowledge of a security vulnerability is power over a developer and their users. It is the fact that someone has invested time into uncovering the vuln which makes it valuable. If they choose to disclose it responsibly, they are surrendering that power and accepting that it will cease to put them in a privileged position. That is something special which doesn’t happen every day. &lt;/p&gt;&lt;p&gt;It is still potent even if discovered using modern tools, or has done so more quickly or easily than before. It’s true that the defending developer may also have access to these tools and may also be able to triage and find the vulnerability more quickly than before. But not all developers will have those tools or the time or knowledge to triage security analysis in the same way. And anyway, the fact is that the vulnerability is available to attackers &lt;em&gt;now&lt;/em&gt; and presumably has been in the past, even if it might reasonably be patched on a shorter timescale than before. &lt;/p&gt;&lt;p&gt;As Filippo puts, it, &lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;In exchange for responsiveness and attribution, they are offering precious insight and the confidentiality we need to ship a fix before attackers ship an exploit.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;I think that holds true, and sacrificing attentiveness would be a shame because it would break the bargain. The bargain doesn’t even really &lt;em&gt;require&lt;/em&gt; responsiveness, that’s just a good convention to follow.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;2-what-can-be-done-once-can-be-done-again&quot;&gt;2: What can be done once can be done again&lt;/h2&gt;&lt;p&gt;If someone has found your vulnerability, others will be able to find it too. Assuming a roughly stable proportion of black-hats to white-hats, the odds of a disclosed vuln being found and abused by others have not changed just because LLMs are available to automate. It might just happen faster, is all. &lt;/p&gt;&lt;p&gt;Filippo makes the point that these things will be triaged and the triage would probably catch the vulnerability anyway. And that’s a good point! But not all tooling is equal, and even with access to the best tools any given project’s triage might just be wrong, or not take account of everything known to the researcher or attacker. So the triage might need to adapt. &lt;label for=&quot;sd-ultimately-if-this&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-ultimately-if-this&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;ultimately if this research was on the &lt;code&gt;#TODO&lt;/code&gt; list anyway, that’s probably a signal that everyone agrees it’s worth addressing. &lt;/span&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;3-abuse-is-also-more-accessible-than-ever&quot;&gt;3: Abuse is also more accessible than ever&lt;/h2&gt;&lt;p&gt;Finally and perhaps a bit more practically, I’m worried that LLMs are not just making vulnerabilities easier to find, but also easier to exploit. Exploiting a software vulnerability has never been an easy task, since it requires a decent depth of understanding even to receive the instructions. But it’s now possible to have LLMs guide and patiently explain the steps, or even automate them for you. To that end, I’m not sure the assumption I mentioned above holds: There may well be proportionately &lt;em&gt;more&lt;/em&gt; black-hatting around if everyone and their dog is able to pick up a CVE and run with it without needing to understand the problem deeply.&lt;/p&gt;&lt;p&gt;I say this last thought is a bit more practical than philosophical, because it doesn’t change whether or not the disclosure is still special. But it might be the sort of thing that affects the analysis. &lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;does-it-matter&quot;&gt;Does it matter?&lt;/h2&gt;&lt;p&gt;Probably not really.&lt;/p&gt;&lt;p&gt;But I do think philosophically, the choices that a stranger makes - first to invest time and tokens into finding a vulnerability, and second to disclose it responsibly, are still a special kind of positive interaction, irrespective of the tools used. &lt;/p&gt;&lt;/section&gt;
</content>
  </entry>
  
  <entry>
    <title>Obfuscated, self-evaluating bash script by CDN Akamai being supplied to consumers via retail stores</title>
    <link href="https://tris.sherliker.net/blog/obfuscated-self-evaluating-bash-script-by-cdn-akamai-being-supplied-to-consumers-via-retail-stores/"/>
    <author>
      <name>Tris Sherliker</name>
      <email>tris@sherliker.net</email>
    </author>
    <updated>2026-07-04T00:00:00Z</updated>
    <id>https://tris.sherliker.net/blog/obfuscated-self-evaluating-bash-script-by-cdn-akamai-being-supplied-to-consumers-via-retail-stores/</id>
    <content type="html">&lt;section&gt;&lt;p&gt;When my wife said to me “Let me show you a t-shirt I saw…”, I wasn’t sure what to expect, but it definitely wasn’t an obfuscated bash script printed on the back designed to print a happy Easter egg message. &lt;/p&gt;&lt;p&gt;&lt;span class=&quot;newthought&quot;&gt;I’m not in the habit&lt;/span&gt; of clickbaity headlines&lt;label for=&quot;sd-i-ve-no-idea-at-all&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-i-ve-no-idea-at-all&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;I’ve no idea at all how many views this site gets, but I’m willing to bet it’s not even double-digit humans per month.&lt;/span&gt; but I can see why subeditors have such fun with them. The title above is, strictly speaking, entirely accurate, but probably not what you think. The obfuscated code in question is actually an easter egg, it’s being supplied via Uniqlo stores on an excellent t-shirt designed by Akamai in support of their &lt;a href=&quot;https://www.uniqlo.com/nl/en/special-feature/peace-for-all&quot;&gt;Peace for All campaign&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;And it’s very cool! The front has a heart in curly braces:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/2026-07-04-tshirt-front.jpg&quot; alt=&quot;Front&quot; /&gt;&lt;/p&gt;&lt;p&gt;While the back has a big alphanumeric block:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/2026-07-04-tshirt-back.jpg&quot; alt=&quot;Back&quot; /&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;is-that--a-shebang&quot;&gt;Is that … a shebang?!&lt;/h2&gt;&lt;p&gt;My wife was right that I’d want to see it. Was that… a shebang? &lt;/p&gt;&lt;p&gt;Take a closer look at the text block: &lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/2026-07-04-cropped-script.jpg&quot; alt=&quot;The Script&quot; /&gt;&lt;/p&gt;&lt;p&gt;Yes, a shebang! On a t-shirt sold in a high street store, no less. And it is clearly a base64 encoded Here string being fed to eval via &lt;code&gt;base64 --decode&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;Interesting. I told my wife &quot;that’s basically how people ship viruses’ and bought it.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;ocr-was-cumbersome&quot;&gt;OCR was cumbersome&lt;/h2&gt;&lt;p&gt;There was good news and bad news: &lt;/p&gt;&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;bad news&lt;/strong&gt; was that base64 hasn’t got error correction, meaning that the transcription would need to be perfect. Sigh. &lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;good news&lt;/strong&gt; was that the string seemed to be intact - at least, it terminated with the expected padding and had matching quotes and braces. This is a good thing because Uniqlo x Akamai sells &lt;a href=&quot;https://www.uniqlo.com/nl/en/products/E459562-000/00?colorDisplayCode=09&amp;#x26;sizeDisplayCode=003&quot;&gt;another design of shirt in the same range&lt;/a&gt; which is plainly &lt;em&gt;incomplete&lt;/em&gt;&lt;label for=&quot;sd-for-example-its&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-for-example-its&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;For example, its imports are truncated and it ends “retu” instead of “return”. This is a pity, because it’s a really nice colour combination and contains the highly idiomatic instruction &lt;code&gt;go doStuff(msg, work...&lt;/code&gt; which anyone can relate to.&lt;/span&gt;, a truncated crop from a wider text block which could never compile. &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;I ran OCR in a few ways: First, using the built-in OCR of the circle-to-search feature on Android, which is often very good. Second, by using Tesseract with a few options and tweaks. And third by running it through Claude. After diffing the three to look for mismatches and getting Claude to output a table of locations for quick scanning, it became trivial but time-consuimg to tidy up the remainder. The resulting string was: &lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-base64&quot;&gt;IyEvYmluL2Jhc2gKCiMgQ29uZ3JhdHVsYXRpb25zISBZb3UgZm91bmQgdGhlIGVhc3RlciBlZ2chIOKdpO+4jwojIOOBiuOCgeOBp+OBqOOBhuOBlOOBluOBhOOBvuOBme+8gemaoOOBleOCjOOBn+OCteODl+ODqeOCpOOCuuOCkuimi+OBpOOBkeOBvuOBl+OBn++8geKdpO+4jwoKIyBEZWZpbmUgdGhlIHRleHQgdG8gYW5pbWF0ZQp0ZXh0PSLimaVQRUFDReKZpUZPUuKZpUFMTOKZpVBFQUNF4pmlRk9S4pmlQUxM4pmlUEVBQ0XimaVGT1LimaVBTEzimaVQRUFDReKZpUZPUuKZpUFMTOKZpVBFQUNF4pmlRk9S4pmlQUxM4pmlIgoKIyBHZXQgdGVybWluYWwgZGltZW5zaW9ucwpjb2xzPSQodHB1dCBjb2xzKQpsaW5lcz0kKHRwdXQgbGluZXMpCgojIENhbGN1bGF0ZSB0aGUgbGVuZ3RoIG9mIHRoZSB0ZXh0CnRleHRfbGVuZ3RoPSR7I3RleHR9CgojIEhpZGUgdGhlIGN1cnNvcgp0cHV0IGNpdmlzCgojIFRyYXAgQ1RSTCtDIHRvIHNob3cgdGhlIGN1cnNvciBiZWZvcmUgZXhpdGluZwp0cmFwICJ0cHV0IGNub3JtOyBleGl0IiBTSUdJTlQKCiMgU2V0IGZyZXF1ZW5jeSBzY2FsaW5nIGZhY3RvcgpmcmVxPTAuMgoKIyBJbmZpbml0ZSBsb29wIGZvciBjb250aW51b3VzIGFuaW1hdGlvbgpmb3IgKCggdD0wOyA7IHQrPTEgKSk7IGRvCiAgICAjIEV4dHJhY3Qgb25lIGNoYXJhY3RlciBhdCBhIHRpbWUKICAgIGNoYXI9IiR7dGV4dDp0ICUgdGV4dF9sZW5ndGg6MX0iCiAgICAKICAgICMgQ2FsY3VsYXRlIHRoZSBhbmdsZSBpbiByYWRpYW5zCiAgICBhbmdsZT0kKGVjaG8gIigkdCkgKiAkZnJlcSIgfCBiYyAtbCkKCiAgICAjIENhbGN1bGF0ZSB0aGUgc2luZSBvZiB0aGUgYW5nbGUKICAgIHNpbmVfdmFsdWU9JChlY2hvICJzKCRhbmdsZSkiIHwgYmMgLWwpCgogICAgIyBDYWxjdWxhdGUgeCBwb3NpdGlvbiB1c2luZyB0aGUgc2luZSB2YWx1ZQogICAgeD0kKGVjaG8gIigkY29scyAvIDIpICsgKCRjb2xzIC8gNCkgKiAkc2luZV92YWx1ZSIgfCBiYyAtbCkKICAgIHg9JChwcmludGYgIiUuMGYiICIkeCIpCgogICAgIyBFbnN1cmUgeCBpcyB3aXRoaW4gdGVybWluYWwgYm91bmRzCiAgICBpZiAoKCB4IDwgMCApKTsgdGhlbiB4PTA7IGZpCiAgICBpZiAoKCB4ID49IGNvbHMgKSk7IHRoZW4geD0kKChjb2xzIC0gMSkpOyBmaQoKICAgICMgQ2FsY3VsYXRlIGNvbG9yIGdyYWRpZW50IGJldHdlZW4gMTIgKGN5YW4pIGFuZCAyMDggKG9yYW5nZSkKICAgIGNvbG9yX3N0YXJ0PTEyCiAgICBjb2xvcl9lbmQ9MjA4CiAgICBjb2xvcl9yYW5nZT0kKChjb2xvcl9lbmQgLSBjb2xvcl9zdGFydCkpCiAgICBjb2xvcj0kKChjb2xvcl9zdGFydCArIChjb2xvcl9yYW5nZSAqIHQgLyBsaW5lcykgJSBjb2xvcl9yYW5nZSkpCgogICAgIyBQcmludCB0aGUgY2hhcmFjdGVyIHdpdGggMjU2LWNvbG9yIHN1cHBvcnQKICAgIGVjaG8gLW5lICJcMDMzWzM4OzU7JHtjb2xvcn1tIiQodHB1dCBjdXAgJHQgJHgpIiRjaGFyXDAzM1swbSIKCiAgICAjIExpbmUgZmVlZCB0byBtb3ZlIGRvd253YXJkCiAgICBlY2hvICIiCgpkb25lCgo=
&lt;/code&gt;&lt;/pre&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;the-decoded-script&quot;&gt;The decoded script&lt;/h2&gt;&lt;p&gt;After Base64 decoding, the resulting script is a welcoming and nicely commented Easter egg:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

# Congratulations! You found the easter egg! ❤️
# おめでとうございます！隠されたサプライズを見つけました！❤️

# Define the text to animate
text=&quot;♥PEACE♥FOR♥ALL♥PEACE♥FOR♥ALL♥PEACE♥FOR♥ALL♥PEACE♥FOR♥ALL♥PEACE♥FOR♥ALL♥&quot;

# Get terminal dimensions
cols=$(tput cols)
lines=$(tput lines)

# Calculate the length of the text
text_length=${#text}

# Hide the cursor
tput civis

# Trap CTRL+C to show the cursor before exiting
trap &quot;tput cnorm; exit&quot; SIGINT

# Set frequency scaling factor
freq=0.2

# Infinite loop for continuous animation
for (( t=0; ; t+=1 )); do
    # Extract one character at a time
    char=&quot;${text:t % text_length:1}&quot;
    
    # Calculate the angle in radians
    angle=$(echo &quot;($t) * $freq&quot; | bc -l)

    # Calculate the sine of the angle
    sine_value=$(echo &quot;s($angle)&quot; | bc -l)

    # Calculate x position using the sine value
    x=$(echo &quot;($cols / 2) + ($cols / 4) * $sine_value&quot; | bc -l)
    x=$(printf &quot;%.0f&quot; &quot;$x&quot;)

    # Ensure x is within terminal bounds
    if (( x &amp;#x3C; 0 )); then x=0; fi
    if (( x &gt;= cols )); then x=$((cols - 1)); fi

    # Calculate color gradient between 12 (cyan) and 208 (orange)
    color_start=12
    color_end=208
    color_range=$((color_end - color_start))
    color=$((color_start + (color_range * t / lines) % color_range))

    # Print the character with 256-color support
    echo -ne &quot;\033[38;5;${color}m&quot;$(tput cup $t $x)&quot;$char\033[0m&quot;

    # Line feed to move downward
    echo &quot;&quot;

done
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The result is a continuous happy sine-wave loop of the campaign message, Peace for All: &lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://tris.sherliker.net/assets/2026-07-04-term-output-static.png&quot; alt=&quot;Peace for All&quot; /&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;detail-the-font-choice&quot;&gt;Detail: The font choice&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Edit: The following font ID is wrong! &lt;a href=&quot;https://news.ycombinator.com/item?id=48829312#48831703&quot;&gt;User ralphinus on Hacker News pointed out &lt;/a&gt; that the font is Roboto Mono. I don’t know how I overlooked the very different &lt;code&gt;g&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I guess Uniqlo is run through Windows though: one thing that struck me was the font, which &lt;del&gt;I’m&lt;/del&gt; &lt;em&gt;I was previously&lt;/em&gt; almost certain is &lt;a href=&quot;https://en.wikipedia.org/wiki/Consolas&quot;&gt;Consolas&lt;/a&gt;&lt;label for=&quot;sd-i-was-fortunate&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sd-i-was-fortunate&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;I was fortunate enough to correspond with the designer, Lucas de Groot, once in relation to a legal case in which someone had used one of his fonts to forge a document. He was very helpful and kind enough to confirm the necessary facts in writing, even though he owed nothing to us. &lt;/span&gt;, which I’m fond of. Note the very shallowly-slashed &lt;code&gt;0&lt;/code&gt;, the lack of serif on the &lt;code&gt;1&lt;/code&gt; and the rounded curves of letters like &lt;code&gt;BDyg&lt;/code&gt; and number &lt;code&gt;2&lt;/code&gt;. It’s striking because it’s primarily a &lt;em&gt;Windows&lt;/em&gt; font, so not the sort of thing I’d expect to see calling Bash. &lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;linux-the-language-of-the-internet&quot;&gt;Linux, the language of the Internet&lt;/h2&gt;&lt;p&gt;Akamai put out a &lt;a href=&quot;https://www.akamai.com/newsroom/press-release/uniqlo-adds-new-akamai-tshirt-to-peace-for-all-collection&quot;&gt;press release&lt;/a&gt; about the shirt when it was released, which is another sort of interesting due to the blend of tech and marketing:&lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;Design message&lt;/p&gt;
&lt;p&gt;More than 25 years ago, Akamai helped make the internet we know today possible. This shirt’s design is a callback to those early days of life online. The light tan color is a reference to the “beige box” plastic casings that housed the early internet computers, and the heart on the front represents how the internet has been used for good all over the world. On the back of the T-shirt is real code. It’s a reference to Linux, the open-source language of the internet. This common language unites Akamai with the world’s top brands and the people they serve, as we work together toward a vision of a safer and more connected world.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2 id=&quot;not-the-first&quot;&gt;Not the first&lt;/h2&gt;&lt;p&gt;I deliberately didn’t search for spoilers at first, but I see that I am of course not the first person to get nerd-sniped by this. &lt;a href=&quot;https://leewc.com/blog/uniqlo-akamai-peace-for-all/&quot;&gt;Wen Chuan Lee&lt;/a&gt; and that post also links to another (against which I’ve cross-checked my transcription above). I’m happy to carry on the chain. &lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=48829312&quot;&gt;Read the discussion of this post on Hacker News, which includes links to more info from the designer and other interesting observations&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;https://tris.sherliker.net/assets/2026-07-04-term-output-recording.webm&quot;&gt;&lt;/video&gt;&lt;/p&gt;&lt;/section&gt;
</content>
  </entry>
</feed>
