{"version":"1.1","title":"benjamin wil","description":"Software developer, technical writer","language":"en","items":[{"id":"https://benjaminwil.info/weblog/i-like-json-feed","url":"https://benjaminwil.info/weblog/i-like-json-feed","external_url":null,"title":"I like JSON Feed","summary":"Recently, I implemented JSON Feed support for my static site generator, Lifer.","image":null,"banner_image":null,"date_published":"2026-06-17 15:24:15 -0700","date_modified":"2026-06-17 15:24:15 -0700","tags":["#<Lifer::Tag:0x00007fffdb1a3528>","#<Lifer::Tag:0x00007fffdb56acb0>"],"language":"en","content_html":"<p>Recently, I implemented <a href=\"https://www.jsonfeed.org/\">JSON Feed</a> support for\nmy static site generator, <a href=\"https://github.com/benjaminwil/lifer\">Lifer</a>. My\nimpression is that, in 2026, JSON Feed is still not widely used, while people\ncontinue to rediscover RSS<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup> thanks to the indie web resurgence\nand an appetite for re-decentralization. <a href=\"https://openrss.org/blog/bluesky-has-launched-rss-feeds\">Bluesky supports RSS</a>;\n<a href=\"https://www.rssboard.org/news/211/every-mastodon-user-has-rss-feed\">Mastodon supports RSS</a>; <a href=\"https://support.substack.com/hc/en-us/articles/360038239391-Is-there-an-RSS-feed-for-my-publication\">Substack supports RSS</a>; even Reddit\nsupports RSS<sup id=\"fnref:2\"><a href=\"#fn:2\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">2</a></sup>—but none of them support JSON Feed.</p>\n\n<p>It makes sense for JSON Feed to be less popular than RSS: it’s not\nnearly as old or entrenched; it was created at a time, pre-Twitter implosion,\nin which feed reading had been subsumed by Twitter; and it doesn’t\noffer much <em>new</em> or <em>different</em> over RSS, so why bother. That said, after\nlooking at my implementations of RSS 2.0 and Atom versus my implementation\nof JSON Feed, I found lots to like about JSON Feed.</p>\n\n<p><a href=\"https://www.jsonfeed.org/2017/05/17/announcing-json-feed.html\">The rationale provided</a> by the authors of the spec isn’t written\nin a persuasive way:</p>\n\n<blockquote>\n  <p>We—Manton Reece and Brent Simmons—have noticed that JSON has become\nthe developers’ choice for APIs, and that developers will often go out of\ntheir way to avoid XML. JSON is simpler to read and write, and it’s less\nprone to bugs.</p>\n</blockquote>\n\n<p>Let me reframe this to be more compelling.</p>\n\n<h2 id=\"json-is-better-than-xml-at-storing-html-as-data\">JSON is better than XML at storing HTML as data</h2>\n\n<p>In an Atom feed, you must encode HTML nodes inside of the <code>&lt;content&gt;</code>\nXML node so that they don’t look like the next XML node in the feed. This\nmeans, if you’re publishing HTML in your feeds, that the XML is even less\nhuman-readable than usual. See this excerpt from my blog’s feed:</p>\n\n<pre><code>  &lt;entry&gt;\n    &lt;content&gt;\n      &amp;lt;p&amp;gt;Here’s another blog post vouching for writing Ruby blocks\n      using the semantic rule. Sometimes called “the Weirich rule”\n      because of &amp;lt;a href=&amp;quot;\n      https://en.wikipedia.org/wiki/Jim_Weirich&amp;quot;&amp;gt;\n      Jim Weirich&amp;lt;/a&amp;gt;’s “Braces vs. Do/End” article&amp;lt;\n      sup id=&amp;quot;fnref:weirich&amp;quot;&amp;gt;&amp;lt; a href=&amp;quot;#fn:weirich&amp;quot;\n      class=&amp;quot;footnote&amp;quot; rel=&amp;quot;footnote&amp;quot;\n      role=&amp;quot;doc-noteref&amp;quot;&amp;gt;1&amp;lt;/a&amp;gt;&amp;lt;/sup&amp;gt; and an issue\n      he filed against &amp;lt;\n      a href=&amp;quot;https://github.com/rubocop/ruby-style-guide/issues/162&amp;quot;&amp;gt;&amp;lt;code&amp;gt;rubocop/ruby-style-guide&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;.\n      The rule unambiguously answers the question posed by Weirich: “When\n      should you use &amp;lt;code&amp;gt;{}&amp;lt;/code&amp;gt; for blocks and when\n      should you use &amp;lt;code&amp;gt;do&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;?”\n      His answer:&amp;lt;/p&amp;gt; &lt;!--…--&gt;\n    &lt;/content&gt;\n</code></pre>\n\n<p>I know you’re thinking that these feeds aren’t meant to be read by humans\nin the raw, so who cares. As a developer, though, wouldn’t you rather deal\nwith simpler raw data? Here’s the same excerpt in JSON Feed (unminified):</p>\n\n<pre><code>\"content_html\":\n  \"&lt;p&gt;Here’s another blog post vouching for writing Ruby blocks using\n  the semantic\\nrule. Sometimes called “the Weirich rule” because\n  of &lt;a href=\\\"https://en.wikipedia.org/wiki/Jim_Weirich\\\"&gt;Jim\n  Weirich&lt;/a&gt;’s\\n“Braces vs. Do/End”\n  article&lt;sup id=\\\"fnref:weirich\\\"&gt;&lt;a\n  href=\\\"#fn:weirich\\\" class=\\\"footnote\\\" rel=\\\"footnote\\\"\n  role=\\\"doc-noteref\\\"&gt;1&lt;/a&gt;&lt;/sup&gt; and an issue he filed against\\n&lt;a\n  href=\\\"https://github.com/rubocop/ruby-style-guide/issues/162\\\"&gt;&lt;code&gt;rubocop/ruby-style-guide&lt;/code&gt;&lt;/a&gt;.\n  The rule unambiguously answers the\\nquestion posed by Weirich:\n  “When should you use &lt;code&gt;{}&lt;/code&gt; for blocks and when\\nshould\n  you use &lt;code&gt;do&lt;/code&gt;/&lt;code&gt;end&lt;/code&gt;?” His answer:&lt;/p&gt; ...\"\n</code></pre>\n\n<h2 id=\"json-is-more-accessible-than-xml\">JSON is more accessible than XML</h2>\n\n<p>JavaScript is one of the most widely-used programming languages in the world,\nand JavaScript Object Notation is a first-class feature of the language. In\na JavaScript context, it’s easy to both generate and parse valid JSON.</p>\n\n<p>Since parsing JSON takes no effort, even client-side in a web browser, I\nfeel there are opportunities for us to go beyond feed reading and aggregation\nwith JSON Feeds. The cost of parsing is so low, and the specified structure\nis simple. Desktop web browsers can even autoformat JSON to be nicely\nhuman readable<sup id=\"fnref:3\"><a href=\"#fn:3\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">3</a></sup>.</p>\n\n<p>New programmers and non-programmers can make sense of JSON, and JSON parsing\ntools, pretty quickly. Feel free to pair this with my “HTML doesn’t need to\nbe escaped in JSON Feed” argument above. RSS is just more abstract to read\nand slightly more error-prone to write. Given this, I think JSON Feed has\nthe accessibility edge over RSS.</p>\n\n<h2 id=\"the-standard-exchange-format-is-json\">The standard exchange format is JSON</h2>\n\n<p>Many popular programming languages besides JavaScript also have first-class\nsupport for JSON. For example, I implemented JSON Feed generation support in\nRuby using <a href=\"https://docs.ruby-lang.org/en/master/JSON.html\">Ruby’s standard JSON library</a>. Writing the implementation\nin Ruby felt no different than doing it in JavaScript.</p>\n\n<p>The reason you’ll find JSON libraries built into so many languages is because\nit’s normal for API services respond to clients in JSON these days. In my\nexperience, XML-based APIs have been eclipsed by JSON-based ones. Even as\nfar back as 2011, a blog post by Dmitriy Samovskiy, <a href=\"http://www.somic.org/2011/06/08/json-vs-xml-in-api/\">“JSON vs. XML in\nAPI,”</a> indicates that developers were realizing that designing JSON-based\nAPIs resulted in a less complex system:</p>\n\n<blockquote>\n  <p>There is no easy and universal way how to represent nested hashes and arrays\nusing XML (if there is, I hope to hear from you about it—I need stable\nlibraries that can convert arrays and hashes to XML and back that could\ninterop among each other for all major programming languages). Of course it’s\npossible and not terribly difficult, but it’s something that one must do.</p>\n\n  <p>Contrast this situation with JSON—you don’t need to worry about this,\nit’s already taken care of for you. The only limitation of JSON that we\nfaced was that JSON doesn’t like integers as hash keys, it wants you to\nconvert them to strings or use an array instead of a hash.</p>\n</blockquote>\n\n<p>I would guess most of the software developers I’ve met and worked with, my\nage or younger, have never had to consume an API that responds in XML. (Even\nmore of them may not know what <a href=\"https://en.wikipedia.org/wiki/SOAP\">SOAP</a> is.)</p>\n\n<p>If JSON is the standard exchange format, it makes sense that websites\nwould benefit from providing content in that format so that content can be\nread… standardly. The longevity and resilience of RSS has made it <em>the\nstandard</em> for website feeds, but we have watched the rest of the Web move\non to JSON for good enough reasons. I’d say “why not JSON Feed?” since it\nalready exists and is well specified.</p>\n\n<h2 id=\"software-developers-are-good-at-working-with-json\">Software developers are good at working with JSON</h2>\n\n<p>Implementing JSON Feed was a breeze. I compared my implementations of Atom,\nRSS, and JSON Feed generation side by side. They’re all shaped the same way,\nand there are only a few more lines of code to required to handle some RSS\nspecification things. What made it a breeze was the simplicity of the JSON\nlibrary API I was using: the public interface is minimal; the method names\nmatch my mental model for working with all kinds of (non-JSON Feed) JSON data.</p>\n\n<p>My comparison revealed to me that the standard Ruby library for RSS is <em>pretty</em>\nbespoke and hasn’t been used by nearly as many people over the years. It’s\nnot a bad library, but there’s so much friction that simply doesn’t exist\nwhen slinging JSON. It’s no contest.</p>\n\n<p>Anyway, this website <a href=\"/feed.json\">now has a JSON Feed</a> if you’d like\nto subscribe to my posts that way.</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>By “RSS,” I really mean “Atom and RSS,” throughout this article. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:2\">\n      <p>I couldn’t find official documentation for\n  this. Just take the URL to any subreddit and add <code>/.rss</code> to the\n  path, i.e. <code>https://www.reddit.com/r/TVTooHigh/.rss</code>. I’ll say, though, that\n  in the past, the few subreddit feeds I subscribed would stop working… for\n  months at a time. It may be more reliable to use a third-party subreddit\n  RSS feed generator, if reliability matters to you. <a href=\"#fnref:2\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:3\">\n      <p>I often use <a href=\"https://firefox-source-docs.mozilla.org/devtools-user/json_viewer/index.html\">Firefox’s JSON viewer</a>.\n  It’s good. <a href=\"#fnref:3\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/ssh-key-agent-management","url":"https://benjaminwil.info/weblog/ssh-key-agent-management","external_url":null,"title":"SSH agent–managed SSH keys","summary":"You probably already know: there’s no excuse to not be using a password manager in 2026.","image":null,"banner_image":null,"date_published":"2026-05-08 16:24:10 -0700","date_modified":"2026-05-08 16:24:10 -0700","tags":["#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>You probably already know: there’s no excuse to not be using a password\nmanager in 2026. If you read my blog regularly, you may even be a person\nactually using a password manager. It’s possible, though, that you don’t\nuse said password manager to manage your SSH keys.</p>\n\n<p>If you didn’t already know <a href=\"https://developer.1password.com/docs/ssh/manage-keys/\">you can manage your SSH credentials seamlessly in\n1Password</a>. You can\ndo it <a href=\"https://github.com/keepassxreboot/keepassxc/blob/52318f4d22c3707dfe1743502d89d6bbc785b2cb/docs/topics/SSHAgent.adoc\">with KeePassXC, too</a>. I’m not going to mention the other\nbig password managers by name, but at least one of them also already has\nbuilt-in SSH agent support. Yes, the managers implement an SSH agent (see\n<a href=\"https://man.openbsd.org/ssh-agent\"><code>ssh-agent</code></a>) and make authenticating\nvia SSH feel kinda like authenticating to Netflix via a web browser.</p>\n\n<p>More than ever, it’s a good idea to <em>not</em> store any credentials (or sensitive\ndata in general) unencrypted on your disks. <em>More than ever</em> because there\nhave been many notable instances of open-source software having recently been\ncompromised via supply-chain attacks and backdoors. Group-IB characterizes\nsupply-chain attacks as <a href=\"https://www.group-ib.com/blog/supply-chain-attack-groups-2026/\">being hyped</a> right now, which is funny and\nhorrifying.</p>\n\n<p>Between all the free-ish tools you use everyday and the LLM-related software\nyour boss pays for, your computer is more an open wound, ready to be infected,\nthan ever. You likely know this, I’m only here to remind you.</p>\n\n<p>If, like me, you manage an environment or two where you don’t want to install\na password manager, and you simply want to avoid leaving SSH private keys in\nplaintext, you can use GPG and a simple shell script to keep your credentials\nsafe from prying mal-processes:</p>\n\n<pre><code>#!/usr/bin/env sh\n#\n# ssh-enc\n#\n# Usage:\n#   ssh-enc &lt;path to GPG-encrypted SSH private key&gt; [SSH arguments]\n# Example:\n#   $ ssh-enc \"$HOME/.ssh/vps.gpg\" benjaminwil@example.com -vvv\n\nencrypted_ssh_private_key_path=\"$1\"\nshift\n\nssh_arguments=\"$@\"\n\neval \"$(ssh-agent -s)\"\nssh-add &lt;(gpg --decrypt \"$encrypted_ssh_private_key_path\")\n\nssh \"$ssh_arguments\"\n</code></pre>\n\n"},{"id":"https://benjaminwil.info/weblog/portable-feature-flags-in-ruby","url":"https://benjaminwil.info/weblog/portable-feature-flags-in-ruby","external_url":null,"title":"Portable feature flags in ten-ish lines of Ruby","summary":"It may make sense to use a mature feature flag library or pay for feature flags as a service in your complex application....","image":null,"banner_image":null,"date_published":"2026-03-21 10:18:36 -0700","date_modified":"2026-03-21 10:18:36 -0700","tags":["#<Lifer::Tag:0x00007fffdb6d9c18>","#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>It may make sense to use a mature feature flag library or pay for feature\nflags as a service in your complex application. That said, you can build\npretty robust feature flags in just a few lines of Ruby:</p>\n\n<pre><code>require \"json\"\n\nmodule Features\n  class &lt;&lt; self\n    def as_json\n      flags = self.public_methods - Object.public_methods - [:as_json]\n      flags\n        .to_h { |method|\n          [method.to_s.sub(\"?\", \"\"), self.public_send(method)]\n        }\n        .to_json\n    end\n\n     def éric_rohmer_mode_enabled? = enabled?(\"ERIC_ROHMER_MODE\")\n\n     private def enabled?(env_string)\n       return false if (value = ENV[env_string]).nil?\n       value != \"false\" &amp;&amp; value.length != 0\n     end\n   end\n end\n</code></pre>\n\n<p>In this example, we track environment variables for each of our feature flags\n(just one, for now: <code>ERIC_ROHMER_MODE</code>). The interface returns a boolean\nvalue when we ask whether the given flag is enabled. Because we’re managing\nthe flags within a single module, we can do nice things such as introduce\nthe <code>Features.as_json</code> method to the current enabled status of all of our\nfeature flags, meaning we can send this data to other systems and to web\nclients more easily:</p>\n\n<pre><code>Features.as_json\n=&gt; \"{\\\"éric_rohmer_mode_enabled\\\":false}\"\n</code></pre>\n\n<p>If you don’t need the portability of JSON, you can\nwrite even fewer lines of Ruby to get the same functionality by relying on\ntruthy and falsey outputs instead of booleans.</p>\n\n<p>As long as you keep higher-complexity methods like <code>Features.as_json</code> to\na minimum, this module can easily grow with you as your need for weirder\nfeature flags increases. If some features should only be available to users\nwith a beta tester role, or you want to expose some functionality when a\ncertain URL parameter is present, it’s just a matter of injecting your user\nobject and your request parameters object:</p>\n\n<pre><code>require \"date\"\nrequire \"json\"\n\nmodule Features\n  ÉRIC_ROHMER_LAUNCH_DAY = Date.new(1920, 03, 21)\n\n  NULL_SCOPE = {\n    url_params: {},\n    user: nil\n  }\n\n  class &lt;&lt; self\n    def as_json(scope = NULL_SCOPE)\n      flags = self.public_methods - Object.public_methods - [:as_json]\n      flags\n        .to_h { |method|\n          [method.to_s.sub(\"?\", \"\"), self.public_send(method, **scope)]\n        }\n        .to_json\n    end\n\n     def éric_rohmer_mode_enabled?(_)\n       enabled?(\"ERIC_ROHMER_MODE\") &amp;&amp;\n         Time.now.to_date &gt;= ÉRIC_ROHMER_LAUNCH_DAY\n     end\n\n     def infinite_money_enabled?(user:, **)\n       enabled?(\"INFINITE_MONEY\") &amp;&amp; !user.nil? &amp;&amp; user.beta_tester?\n     end\n\n     def preview_mode_enabled?(url_params:, **)\n       enabled?(\"PREVIEW_MODE\") &amp;&amp; url_params[:preview] == \"yes\"\n     end\n\n     private def enabled?(env_string)\n       return false if (value = ENV[env_string]).nil?\n       value != \"false\" &amp;&amp; value.length != 0\n     end\n   end\n end\n</code></pre>\n\n<p>As long as you’re keeping track of potential dependencies (<code>NULL_SCOPE</code> in\nthis example) and passing in reasonable default values, <code>Features.as_json</code>\nstill works sans arguments, and each flag check can independently be as\ncomplex as you’d like it to be.</p>\n\n<pre><code>JSON.parse Features.as_json\n=&gt;\n{\"éric_rohmer_mode_enabled\"=&gt;false,\n \"preview_mode_enabled\"=&gt;false,\n \"infinite_money_enabled\"=&gt;false}\n\nJSON.parse Features.as_json(user: beta_tester, url_params: {})\n=&gt;\n{\"éric_rohmer_mode_enabled\"=&gt;false,\n \"preview_mode_enabled\"=&gt;false,\n \"infinite_money_enabled\"=&gt;true}\n</code></pre>\n\n<p>I’ve used keyword arguments in my interface because I prefer them to positional\narguments. This ensures the flag method arguments remain legible\nin your application code and are easy comprehend by other readers. But as\nyou can see, keyword arguments make flags a bit more annoying to write once\nyou’ve introduced dependencies.</p>\n\n<p>The most awkward thing here is that even feature flags methods that\ndon’t require dependency injection must define an argument (<code>_</code> or\n<code>_unused</code>). The second most awkward thing is that, only because we’re\nusing keyword arguments, we need to pass a double-splat argument (<code>**</code>)\nto ensure, when <code>Features.as_json</code> is computing the given dependencies for\neach flag dynamically, irrelevant arguments are ignored without raising an\n<code>ArgumentError</code>. Luckily, the relevant dependencies remain very, very visible\nto anyone else reading.</p>\n\n<p>Every codebase I’ve worked on deals with feature flags a little bit\ndifferently. I’d love to hear about what’s different in your\napplication’s. (Send me a message!)</p>\n"},{"id":"https://benjaminwil.info/weblog/ruby-semantic-blocks","url":"https://benjaminwil.info/weblog/ruby-semantic-blocks","external_url":null,"title":"Semantic style Ruby blocks","summary":"Here’s another blog post vouching for writing Ruby blocks using the semantic rule.","image":null,"banner_image":null,"date_published":"2026-03-08 16:06:46 -0700","date_modified":"2026-03-08 16:06:46 -0700","tags":["#<Lifer::Tag:0x00007fffdb6d9c18>","#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>Here’s another blog post vouching for writing Ruby blocks using the semantic\nrule. Sometimes called “the Weirich rule” because of <a href=\"https://en.wikipedia.org/wiki/Jim_Weirich\">Jim Weirich</a>’s\n“Braces vs. Do/End” article<sup id=\"fnref:weirich\"><a href=\"#fn:weirich\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup> and an issue he filed against\n<a href=\"https://github.com/rubocop/ruby-style-guide/issues/162\"><code>rubocop/ruby-style-guide</code></a>. The rule unambiguously answers the\nquestion posed by Weirich: “When should you use <code>{}</code> for blocks and when\nshould you use <code>do</code>/<code>end</code>?” His answer:</p>\n\n<ul>\n  <li>Use braces (<code>{}</code>) for blocks that return values.</li>\n  <li>Use keywords (<code>do</code>/<code>end</code>) for blocks executed for side effects.</li>\n</ul>\n\n<h2 id=\"an-explanation\">An explanation</h2>\n\n<p>Let’s say we were iterating over some movies in order to print out their titles:</p>\n\n<pre><code>films = [\n  \"A Tale of Springtime\",\n  \"A Tale of Winter\",\n  \"A Summer's Tale\",\n  \"A Tale of Autumn\"\n]\n\nfilms.each do |title|\n  puts title\nend\n</code></pre>\n\n<p>An <code>#each</code> block only ever executes for side effects and never returns a\nvalue we can do stuff with. If we wanted to pre-format our list\nof films, we would need to iterate in such a way that mutates our film list\n(or creates a new list) before printing the films out:</p>\n\n<pre><code>films.map! { |title|\n  title.upcase\n}\n\nfilms.each do |title|\n  puts title\nend\n</code></pre>\n\n<p>At a glance, a reader can see two different types of blocks performing two\ndifferent functions: one mutates data; the other is executed for side effects\n(printing out a list of films). An author not using the semantic rule might\nhave written this:</p>\n\n<pre><code>films.map! { |title| title.upcase }\nfilms.each { |title| puts title }\n</code></pre>\n\n<p>Or this:</p>\n\n<pre><code>films.map! do |title|\n  title.upcase\nend\n\nfilms.each do |title|\n  puts title\nend\n</code></pre>\n\n<p>Both of these are readable but do not communicate intent as clearly as the\nsemantic style blocks. My primary goal when authoring code is to communicate\nmy intent to other readers, so I appreciate the ability to be as precise\nin as few characters as possible.</p>\n\n<h2 id=\"criticisms-of-the-style\">Criticisms of the style</h2>\n\n<p>To me, there are two compelling reasons to be critical of semantic style\nblocks: the readability of <code>do</code>/<code>end</code> one-liners; and the inability of\nautomated tools to format Ruby code consistently based on the semantic\nrule. I can agree that, sometimes, one-liners meant to execute side effects\nwould make reading code more difficult:</p>\n\n<pre><code>films.each do |title| puts title end\n# is less readable than:\nfilms.each { |title| puts title }\n</code></pre>\n\n<p>But Ruby is so expressive that, in the off-chance you need to write a\n<code>do</code>/<code>end</code> one-liner, I’m confident there are other ways of achieving better\nreadability without ditching the rule:</p>\n\n<pre><code>films.each do |title| puts(title) end\n</code></pre>\n\n<p>As for auto-formatting Ruby code while abiding by the semantic rule, this seems\nlike a solvable problem in the long term. The “problem” is that Ruby is\n“too” expressive, and the tooling would have to understand a lot about the\nprogram and the author’s intent to reformat to braces or <code>do</code>/<code>end</code> correctly.</p>\n\n<p>There is <a href=\"https://github.com/standardrb/standard/issues/109\">an interesting issue filed against\n<code>standardrb</code></a> discussing\nthis. And, as of 1.0.0, <code>standardrb</code> has a relaxed, <a href=\"https://github.com/standardrb/standard/pull/263\">“let the author\nchoose”</a> approach to this\nblock syntax. If you’re developing an application and your Ruby code is\nauto-formatted, I hope you will still choose to be intentional whenever\nyou’re writing not-auto-formattable code.</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:weirich\">\n      <p>Weirich’s blog is no longer online but is <a href=\"https://web.archive.org/web/20140117145536/http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc\">archived by the Wayback\n        Machine</a>. <a href=\"#fnref:weirich\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/vff-2026","url":"https://benjaminwil.info/weblog/vff-2026","external_url":null,"title":"Victoria Film Festival 2026","summary":"This month was the 32nd occurrence of the Victoria Film Festival here in Victoria, British Columbia.","image":null,"banner_image":null,"date_published":"2026-02-20 18:47:33 -0800","date_modified":"2026-02-20 18:47:33 -0800","tags":["#<Lifer::Tag:0x00007fffdb586e10>"],"language":"en","content_html":"<p>This month was the <span style=\"font-variant: small-caps;\">32<sup>nd</sup>\n</span> occurrence of the <a href=\"https://www.victoriafilmfestival.com\">Victoria Film\nFestival</a> here in Victoria,\nBritish Columbia. It is likely <a href=\"https://cheknews.ca/packed-theatres-mark-record-breaking-victoria-film-festival-1305971/\">the best-selling VFF in the history of the\nfestival</a> and featured ninety-one feature-length films from twenty-five\ncountries. For a small city-like region like Greater Victoria, the festival\noperates at a higher level than we really deserve, despite the criticism\nthat it’s “just” a “greatest hits” of other, larger 2025 film fests. It’s\nthe best VFF that I’ve personally attended, and I think next year is probably\ngonna be even better.</p>\n\n<p>Since I live and work in Victoria and was just living my normal life, I could\nonly attend a handful of (ten) shows in the evenings, but I overheard others\nbragging about seeing twenty—and even thirty—movies over the course of\nthe ten-day event. Do what you will with it: this article is just a rundown\nof the films I saw and how much I’d recommend them. We’re doing nebulous\nstar ratings from between one and four stars\n(i.e. <span aria-label=\"4 out of 4 stars\" class=\"star-rating\">★★★★</span>)\nthat take into account my enjoyment of the work and my enjoyment of the\nfestival screening.</p>\n\n<h2 id=\"sunset\">100 Sunset</h2>\n\n<p><em>Kunsang Kyirong, 2025, Canada</em></p>\n\n<p>A Canadian immigrant story that I personally haven’t seen before, <em>100\nSunset</em> is focused on the Tibetan diaspora in Parkdale, Toronto. Kyirong’s\nquiet directorial debut is bolstered by veteran (as far as I’m concerned)\ncinematographer <a href=\"https://www.nikolaymichaylov.com/\">Nikolay Michaylov</a>’s\neffortless ability to make you feel like you’re in the subject’s head.  It is\nfull of challenging asshole characters and interesting story-decisions.\n<span aria-label=\"2.5 out of 4 stars\" class=\"star-rating\">★★½</span></p>\n\n<h2 id=\"nirvanna-the-band-the-show-the-movie\">Nirvanna the Band the Show the Movie</h2>\n\n<p><em>Matt Johnson, 2025, Canada</em></p>\n\n<p>I went in not having consumed any of <a href=\"https://nirvannathebandthe.show/episodes/#webseries\">the original web\nseries</a> or <a href=\"https://nirvannathebandthe.show/episodes/#tv_show\">the television show</a>. I was\nappeased, as were my friends who <em>love</em> the antecedent content. I really hope\nthat the distributed cut of the movie will also include actual <em>Back to the\nFuture</em> score samples.  If you’re a sucker for time travel, gonzo filmmaking,\nor buddy comedies, you will have a good time.\n<span aria-label=\"3.5 out of 4 stars\" class=\"star-rating\">★★★½</span></p>\n\n<h2 id=\"beautiful-and-neat-room\">Beautiful and Neat Room</h2>\n\n<p><em>Maria Petschnig, 2025, United States</em></p>\n\n<p>An unhinged tale about a working artist who can’t afford her Brooklyn\napartment without short-term renting out her spare room to other people who\ncan’t afford their own Brooklyn apartments. The principal actress, Charlotte\nAubin, makes this work despite some of the dialogue (with a venti-sized\ncast of supporting actors) smelling slightly undercooked. You <em>will</em> leave\nhating every roommate you’ve ever had.  This was the first, and only, film I\nsaw at the makeshift thirtyish-seater cinema-venue Toaster Rocket located\nat <a href=\"https://www.printhole.ca/\">Print Hole</a>. I gotta say, this was a good\nvenue. Maybe even better than the <em>real cinema</em> Screen 5 at the Capitol 6\nwhere <em>100 Sunset</em> screened.<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup>\n<span aria-label=\"2.5 out of 4 stars\" class=\"star-rating\">★★½</span></p>\n\n<h2 id=\"pillion\">Pillion</h2>\n\n<p><em>Harry Lighton, 2025, United Kingdom &amp; Ireland</em></p>\n\n<p>The crowd loved it, and it was heartwarming. This is incredible considering the\nmovie focuses on a BDSM relationship, which is an intense subculture that I’m\npositive ninety percent of the audience, including myself, know nothing about.\nA feat. Experiencing the narrative through the narrow, naive point of view\nof our protagonist, Harry, will remain burned into my long-term memory.\n<span aria-label=\"3 out of 4 stars\" class=\"star-rating\">★★★</span></p>\n\n<h2 id=\"blue-heron\">Blue Heron</h2>\n\n<p><em>Sophy Romvari, 2025, Canada &amp; Hungary</em></p>\n\n<p>Like <em>100 Sunset</em>, this one is another feature-length debut by a Canadian\nwoman-filmmaker. It amazingly, deservedly, has already been acquired for\ndistribution by Janus Films. It’s a semi-autobiographical story about\na Hungarian-Canadian family whose oldest child is struggling with mental\nillness. It brings a sharp, fresh perspective to the banal family tragedy\nmovie we’ve seen many times over, and it incorporates both narrative and\ndocumentary elements in a surprisingly uncomplicated way. Despite the things\nI really didn’t like about it (millenial needle drops; [spoiler redacted]),\nit is probably my number one pick from the festival.\n<span aria-label=\"4 out of 4 stars\" class=\"star-rating\">★★★★</span></p>\n\n<h2 id=\"levers\">Levers</h2>\n\n<p><em>Rhayne Vermette, 2025, Canada</em></p>\n\n<p>I was excited and primed for this, having seen Vermette’s debut feature\n<a href=\"https://en.wikipedia.org/wiki/Ste._Anne_(film)\"><em>Ste. Anne</em></a>\na couple of years ago. This screening was in collaboration\nwith local events promoter and zine-maker <a href=\"https://destroyedcinema.neocities.org/\"><em>Destroyed\nCinema</em></a>. <em>Destroyed</em> programmed this\nscreening to be followed by live music, which rocks. I think this complemented\nthe film a lot. <em>Levers</em> kinda gives you a Guy Madden-high as you follow\ndozens of (almost a hundred?) extras in rural Manitoba during a mysterious\npseudo-apocolyptic solar eclipse, leaving the town in darkness for seemingly a\n<em>very</em> long time. It was purportedly filmed <a href=\"https://www.thestar.com/entertainment/tiff/tiff-2025-this-surreal-canadian-film-was-shot-on-broken-cameras-and-based-on-tarot/article_74f4f2dd-3835-4217-ad16-82665d84a7fe.html\">on broken cameras</a>, though\nI don’t think that stands out as much as it just having a bedroom-filmmaker,\nno-lighting, 1980s made-for-television look. There are also tarot cards\ninvolved.\n<span aria-label=\"4 out of 4 stars\" class=\"star-rating\">★★★★</span></p>\n\n<h2 id=\"rose-of-nevada\">Rose of Nevada</h2>\n\n<p><em>Mark Jenkin, 2025, United Kingdom</em></p>\n\n<p>A perfect follow-up to <em>Levers</em>, <em>Rose of Nevada</em> also looks like a cursed\n1980s television show episode, albeit a bit more crackerjack. The gentility\nof the fishing village setting and warm, vintage look  makes you forget that\nthis is a hard <em>The Twilight Zone</em> episode. By “hard,” I mean good.\n<span aria-label=\"4 out of 4 stars\" class=\"star-rating\">★★★★</span></p>\n\n<h2 id=\"the-blue-trail\">The Blue Trail</h2>\n\n<p><em>Gabriel Mascaro, 2025, Brazil</em></p>\n\n<p>A dystopian-future movie that’s more character than genre, and I appreciate\nthat the character also happens to be a seventy-five year old woman. This\npremise alone gets at something we deserve more of in a time when nearly all of\nour genre movies are about rich people who are played by actors who are rich people\nwho, at some point, have been in a Marvel movie.\n<span class=\"star-rating\">★★★</span></p>\n\n<h2 id=\"a-useful-ghost\">A Useful Ghost</h2>\n\n<p><em>Ratchapoom Boonbunchachoke; 2025; Thailand, France, Singapore &amp; Germany</em></p>\n\n<p>Another directorial debut. I look forward to seeing more films from\nBoonbunchachoke, but unfortunately I gotta be mean about this one. It’s\na black comedy that isn’t very funny and is probably an hour too long. It\nseems to me that there were too many cooks in the production-kitchen, which\nled to a lot of independently interesting story-ingredients being forced into\nan ambitious, professional, but ultimately unseasoned and conventional stew.\n<span aria-label=\"2 out of 4 stars\" class=\"star-rating\">★★</span></p>\n\n<h2 id=\"a-poet\">A Poet</h2>\n\n<p><em>Simón Mesa Soto; 2025; Colombia, Germany &amp; Sweden</em></p>\n\n<p>To me, this feels like a 2000s indie comedy revival movie. It was revitalizing\nto see a two-hour movie about such a pathetic and misguided person with <em>no\njokes</em> in it, but formally this movie has almost nothing going on.\n<span aria-label=\"2 out of 4 stars\" class=\"star-rating\">★★</span></p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>Not a huge compliment, but still. Screen 5, unfortunately, is <em>the\n  worst</em>, smallest, dimly-lit cinema experience you’ll have in the city. You\n  can see and hear the blood orange <em>EXIT</em> signs more easily than you can the\n  movie you’re there to see. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/new-website","url":"https://benjaminwil.info/weblog/new-website","external_url":null,"title":"New website","summary":"Today I’m launching my website redesign. I hope that you like it.","image":null,"banner_image":null,"date_published":"2026-01-26 08:20:59 -0800","date_modified":"2026-01-26 08:20:59 -0800","tags":[],"language":"en","content_html":"<p>Today I’m launching my website redesign. I hope that you like it. Comparing\nthe new design to the old one<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup>, my design seems to accidentally commemorate\nthe soft ending of my career as a techincal writer. (I continue to search for\nand take software development roles.) We’ve gone from “bold and friendly” to\n“brutal and web-traditional” as I transformed from curious observer of software\nto grisled maintainer of software. The purple accent is gone and has been\nreplaced with blues and blacks (in light mode) and yellows (in dark mode),\nand the IBM Plex Sans typeface has been replaced by your browser’s default\nserif typeface. For most of you, that’s probably Times New Roman, bread\nnull butter. “Times New Roman,” <a href=\"https://practicaltypography.com/a-brief-history-of-times-new-roman.html\">writes typographer Matthew Butterick</a>,\n“connotes apathy.” While I’d often agree, I wanna ask him if all stoicism is\napathy, then? I hope my redesign broadcasts to readers my pragmaticism and\nconnects me to the ancestral proto-social web where hobbyists and developers\nshared knowledge and experience for free, openly, via HTTP and RSS.</p>\n\n<p>With the redesign comes new pages, as well: <a href=\"/colophon\">the colophon</a>.</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>Here’s <a href=\"https://web.archive.org/web/20230528122559/https://benjaminwil.info/weblog/providence-rhode-island/\">an example webpage archived by Archive.org</a>. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/2025-film","url":"https://benjaminwil.info/weblog/2025-film","external_url":null,"title":"The best films I saw: 2025 edition","summary":"As always, in an unranked order, here are the thirty best movies I was able to watch in 2025.","image":null,"banner_image":null,"date_published":"2025-12-31 12:00:00 -0700","date_modified":"2025-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>As always, in an unranked order, here are the thirty best movies I was able\nto watch in 2025. This list was also <a href=\"https://letterboxd.com/benjaminwil/list/top-thirty-2025/\">published on Letterboxd</a>.</p>\n\n<p>I don’t think this year’s list is particularly interesting, except in that\nHong Sang-soo has three entries and there are a couple (<em>Aftersun</em>,\n<em>Sexy Beast</em>) directorial debuts in here. If I had to throw these all out\nand pick out only one it’d be Haneke’s <em>Benny’s Video</em>.</p>\n\n<p>Here are links to previous lists: <a href=\"/weblog/2024-film\">2024</a>,\n<a href=\"/weblog/2023-film\">2023</a>, <a href=\"/weblog/2022-film\">2022</a>, <a href=\"/weblog/2021-film\">2021</a>,\n<a href=\"/weblog/2020-film\">2020</a>, <a href=\"/weblog/2019-film\">2019</a>,\n<a href=\"/weblog/2018-film\">2018</a>, <a href=\"/weblog/2017-film\">2017</a>.</p>\n\n<ul>\n  <li>Charlotte Wells: <em>Aftersun</em>, 2022</li>\n  <li>Larry Clark: <em>Another Day in Paradise</em>, 1998</li>\n  <li>Michael Haneke: <em>Benny’s Video</em>, 1992</li>\n  <li>Jack Dunphy: <em>Bob’s Funeral</em>, 2024</li>\n  <li>Hong Sang-soo: <em>By the Stream</em>, 2024</li>\n  <li>Adam Curtis: <em>Can’t Get You Out of My Head</em>, 2021</li>\n  <li>Agnès Varda: <em>Cléo from 5 to 7</em>, 1962</li>\n  <li>Bill Duke: <em>Deep Cover</em>, 1992</li>\n  <li>Sidney Lumet: <em>Dog Day Afternoon</em>, 1975</li>\n  <li>Stanley Kwan Kam-Pang: <em>Full Moon in New York</em>, 1989</li>\n  <li>Tracey Todd: <em>The Flavor of Cassava Leaf Over Rice</em>, 2025</li>\n  <li>Sam Crane, Pinny Grylls: <em>Grand Theft Hamlet</em>, 2024</li>\n  <li>Hong Sang-soo: <em>In Another Country</em>, 2012</li>\n  <li>Leos Carax: <em>It’s Not Me</em>, 2024</li>\n  <li>Clint Eastwood: <em>Juror #2</em>, 2024</li>\n  <li>Werner Herzog: <a href=\"https://en.wikipedia.org/wiki/Lessons_of_Darkness\"><em>Lessons of Darkness</em></a>, 1992</li>\n  <li>Alain Guiraudie: <em>Misericordia</em>, 2024</li>\n  <li>Kelly Reichardt: <em>The Mastermind</em>, 2025</li>\n  <li>Norman Jewison: <em>Moonstruck</em>, 1987</li>\n  <li>Richard Linklater: <em>Nouvelle Vague</em>, 2025</li>\n  <li>Wim Wenders: <a href=\"http://www.cineoutsider.com/reviews/dvd/r/room_666.html\"><em>Room 666</em></a>, 1982</li>\n  <li>Jonathan Glazer: <em>Sexy Beast</em>, 2000</li>\n  <li>Adam Curtis: <a href=\"https://jacobin.com/2025/07/adam-curtis-y2k-blair-mcqueen\"><em>Shifty</em></a>, 2025</li>\n  <li>David Cronenberg: <em>The Shrouds</em>, 2024</li>\n  <li>Kristoffer Borgli: <em>Sick of Myself</em>, 2022</li>\n  <li>Ryan Coogler: <em>Sinners</em>, 2025</li>\n  <li>Boris Lojkine: <em>Souleymane’s Story</em>, 2024</li>\n  <li>Johan Grimonprez: <em>Soundtrack to a Coup d’Etat</em>, 2024</li>\n  <li>Hong Sang-soo: <a href=\"https://thetake-up.com/a-travelers-needs/\"><em>A Traveler’s Needs</em></a>, 2024</li>\n  <li>Tsai Ming-laing: <em>The Wayward Cloud</em>, 2005</li>\n</ul>\n"},{"id":"https://benjaminwil.info/weblog/porto","url":"https://benjaminwil.info/weblog/porto","external_url":null,"title":"Porto, Portugal","summary":"After EuRuKo in Viana do Castelo, I spent some time in Porto.","image":null,"banner_image":null,"date_published":"2025-10-29 18:06:14 -0700","date_modified":"2025-10-29 18:06:14 -0700","tags":["#<Lifer::Tag:0x00007fffdb6ef298>","#<Lifer::Tag:0x00007fffdb6eed20>"],"language":"en","content_html":"<p>After <a href=\"https://2025.euruko.org\">EuRuKo</a> in <a href=\"/weblog/viana-do-castelo\">Viana do\nCastelo</a>, I spent some time in Porto. In Viana do\nCostelo, some locals said that Porto is not as tourism-oriented as Lisbon.\nIf that’s true, I <em>can’t imagine</em> how tourist-friendly Lisbon must be. I stayed\nnear the historic centre of Porto, and it was quite touristic. The Wikipedia\narticle about Porto has <a href=\"https://en.wikipedia.org/wiki/Porto#Tourism\">a little tourism\nsection</a> with links to articles and\nstudies that indiciate that Porto has been fundamentally changed by an increase\nto tourism over the last twenty years. As a tourist-foreigner there, I can’t\ncomplain: it was an easy place to be a tourist.</p>\n\n<p>Even on the outside of mainstream tourism destinations, Porto caters well to\nforeigners. For example, all of <a href=\"https://cinematrindade.pt\">Cinema Trindade</a>’s\npromotional and advertising materials were crystal clear about which films were\nbeing shown in English or had English subtitles available. Across the street\nfrom Cinema Trindade was a wine bar (<strong>FUNQ</strong>) operated by and filled with Porto\nexpatriates. <a href=\"https://www.batalhacentrodecinema.pt\">Batalha Centro de Cinema</a>, a\nslightly more tourist-oriented cinema and cultural centre, seemed to have one\nAnglo-friendly showing every night of the week.</p>\n\n<p>So Porto was a hospitable, pretty unique, and a very laid back place\nto take a vacation. If you’re going to Porto, I have a few recommendations:</p>\n\n<ul>\n  <li>I already mentioned <strong>The Batalha Centro de Cinema</strong>, which is not only a\ntwo-screen cinema but a cinema bookstore, bar, and gallery. There were posters\nall over the city  for their David Bowie film series which was happening over\nthe course of three or four months. Only having visited here twice, I don’t\nknow the true health of this organization, but it gives me hope that the\ncinema isn’t actually dying. The book shop was special, as I don’t usually see\nso much literature dedicated to film in a single place.</li>\n  <li>The <strong>Guindalense Futebol Clube</strong> is a mostly outdoor pub on the edge of a\ncliff that looks out over the historic Dom Luís I Bridge and Vila Nova de Gaia\nand serves traditional Portuguese hotdogs and sandwiches. It’s a great view\nand a nice, cool place to sit.</li>\n  <li><strong><a href=\"https://www.serralves.pt/en/\">Serralves</a></strong> is a great contemporary art museum.\nThe programming that was on during my visit featured artists from all over the\nworld, but to me the most interesting features were both Portuguese\nfilmmakers. First, the permanant <a href=\"https://www.serralves.pt/en/ciclo-serralves/manoel-de-oliveira-exposicao-permanente/\">Casa do Cinema Manoel de\nOliveira</a>\nroom and theatre, which celebrates the late Porto director and writer. In\naddition to bits of the filmmaker’s personal art collection and a synchronized\nprojection of selected works, there is a video-library wall where visitors can\nwatch entire films and browse information about Oliveira’s filmography.\nSecond, <em><a href=\"https://www.serralves.pt/en/ciclo-serralves/0606-uma-coisa-do-outro-mundo/\">Uma Coisa do Outro\nMundo</a>\n[A Thing From Another World]</em>, a video installation by Jorge Jácome featuring\nfaux-documentary loops featuring disturbing (but funny) military personnel\nencounters with aliens.</li>\n  <li><strong><a href=\"https://www.torto-porto.com/\">Torto</a></strong> is an excellent cocktail bar. If you\nonly go to one, make it this one.</li>\n  <li>If you’re looking for some gentle breakfast or lunch near Cedofeita, go to\n<strong>Hakko</strong>, a tiny lunch place with exceptional specialty coffee, a great plate\nof Turkish eggs, and a great record collection, or <strong>Bicho</strong>, a bright bakery\nand cafḗ just a block away.</li>\n  <li>If you’re still in Cedofeita, go to the <strong>Catraio</strong> beer garden for a huge\nselection of craft beer or <strong>Genuíno</strong> for an effortless family-style dinner\npaired with natural wines.</li>\n  <li>Also in the Cedofeita neighbourhood, <strong><a href=\"https://www.materiaprima.pt/\">Materia\nPrima</a></strong> is my favourite type of book and record\nshop. From their website: “Our interests are broadband, and not focused on any\nparticular aesthetics. We operate with the most expansive and inclusive\ndefinition of culture, and work to make accessible to a widest public, the most\nadventurous, experimental, innovative and sometimes exotic artists, musicians,\nindependent labels and publishers.”</li>\n  <li>Pastel de nata is a pastry that is literally everywhere in Portugal, it seems.\n<strong>Manteigaria</strong> is a chain of bakeries that made the best ones I tried. But\nhonestly, each and every one I had was pretty good.</li>\n</ul>\n"},{"id":"https://benjaminwil.info/weblog/viana-do-castelo","url":"https://benjaminwil.info/weblog/viana-do-castelo","external_url":null,"title":"Viana do Castelo, Portugal","summary":"I was at EuRuKo last month, held in a small city in the Norte Region of Portugal called Viana do Castelo.","image":null,"banner_image":null,"date_published":"2025-10-01 14:02:53 -0700","date_modified":"2025-10-01 14:02:53 -0700","tags":["#<Lifer::Tag:0x00007fffdb6ef298>","#<Lifer::Tag:0x00007fffdb6eed20>"],"language":"en","content_html":"<p>I was at <a href=\"https://2025.euruko.org\">EuRuKo</a> last month, held in a small city in\nthe Norte Region of Portugal called Viana do Castelo. The conference was held in\nthe Centro Cultural de Viana do Castelo, which is a really open, really\nimpressive events venue and cultural centre built close to mouth of the River\nLima into the Atlantic Ocean.</p>\n\n<p>The word “castelo” translates to “castles,” and, yes, there are many historic\ncastles and castle-like buildings throughout the city and larger Viana do\nCastelo district. If EuRuKo hadn’t been scheduled here, it’s unlikely that I\nwould have ever known to come here, but I’m glad I did.</p>\n\n<p>The fact that everyone front-of-house in the restaurants spoke English\nconfidently also tells me that this <em>is</em> a destination for tourists, especially\nconsidering that this was less true in the other smaller municipalities I visited\nthroughout the Norte Region of Portugal. This is probably also because it’s a\ndestination on the <a href=\"https://en.wikipedia.org/wiki/Camino_de_Santiago\">Camino de\nSantiago</a>. So what I’m trying\nto say is that it was an exceptional place for a foreigner like me to visit for\na couple of days.  If you’re going to visit Viana do Castelo, I can offer a few\nrecommendations:</p>\n\n<ul>\n  <li><strong>Sanctuarium</strong> is a bar and café at the top of the mountain of Santa Luzia, a\nshort walk up from the towering Sanctuary of the Sacred Heart of Jesus.\nThere’s a both a steep staircase and a funicular operated by the Church that\ncan be used to get to the summit. Go to Sanctuarium on a clear day so you can\nsee the city and the water down below. The garden seating here is enviable,\nand many locals had drove up to the top of the mountain to picnic.</li>\n  <li><strong>Pacóvio</strong> is a tiny wine and tapas bar not far from the Centro Cultural. I\nfound no better place to try the regional wine and low-key local food. I think\nit’s owner-operated, with just a single couple running the front-of-house and\nback-of-house by themselves.</li>\n  <li><strong>Peloton Coffee and Cycling</strong> is a chill, slow coffee place if you’re in need\nof specialty coffee.</li>\n  <li><strong>Ribeiro’s Brewers</strong> is a craft beer bar with an always-fresh tap list. When\nI visited, there were plenty small-batch Portuguese, Spanish, and German beers\non the menu, and the staff was pretty excited to talk beer.</li>\n</ul>\n"},{"id":"https://benjaminwil.info/weblog/rails-routing-constraints","url":"https://benjaminwil.info/weblog/rails-routing-constraints","external_url":null,"title":"Catch-all routes and routing constraints in Rails applications","summary":"I’ve worked with more than one Ruby on Rails application that has a catch-all GET route at the end of its config/routes.r...","image":null,"banner_image":null,"date_published":"2025-09-19 08:48:50 +0100","date_modified":"2025-09-19 08:48:50 +0100","tags":[],"language":"en","content_html":"<p>I’ve worked with more than one Ruby on Rails application that has a catch-all\n<code>GET</code> route at the end of its <code>config/routes.rb</code> file:</p>\n\n<pre><code>Rails.application.routes.draw do\n  resources :posts\n  resources :users\n\n  # This route is defined after all other routes as a catch-all.\n  get \"/*path\", to: \"fallbacks#show\"\nend\n</code></pre>\n\n<p>What this means is that there is a <code>FallbacksController</code> that handles any\nrouting that isn’t already handled by previously-defined routes. In this simple\nexample, a path like <code>/posts/123</code>, <code>/posts/doesnt-exist</code>, or <code>/users/brock</code> would\nbe rightly handled by the resource routes that have been defined, but some other\npath like <code>/about</code> or <code>/contact</code> would be routed through\n<code>FallbacksController#show</code>. If the fallbacks controller becomes responsible for\nfiguring out what content the user wants to view <em>or</em> rendering some other page\nlike a 404 page:</p>\n\n<pre><code>class FallbacksController &lt; ApplicationController\n  rescue_from ActiveRecord::RecordNotFound, with: :render_404\n\n  def show\n    # If a page with the given path cannot be found, `#find_by!`\n    # raises an `ActiveRecord::RecordNotFound` exception.\n    @page = Page.find_by!(path: params[:path])\n  end\nend\n</code></pre>\n\n<p>This simple controller action looks the same way many other simple controller\nactions look, where the main difference is that we’re handling requests for any\npath not already handled by other routes. <code>/about</code> would route to our static\npage with a <code>#path</code> attribute of <code>/about</code>. <code>/page-that-doesnt-exist</code> would route\nto a 404.</p>\n\n<h2 id=\"when-a-catch-all-route-accumulates-complexity\">When a catch-all route accumulates complexity</h2>\n\n<p>But the applications I’ve worked on that have implemented a catch-all route like\nthis don’t intend to just serve content for <code>/about</code> or <code>/contact</code> pages. They\nall have implemented the catch-all so that they can present connected groups of\npages that have a tree-like structure, like a taxon tree:</p>\n\n<pre><code>/unisex\n└── /unisex/jeans\n    └── /unisex/jeans/raw\n└── /unisex/tops\n    └── /unisex/tops/oversized\n</code></pre>\n\n<p>And using this taxon tree, they often want to present increasingly filtered-down\ngroups of products for a product listing page.</p>\n\n<p>The Rails applications I’ve worked on that provide this catch-all route have all\nstuffed a lot of complexity into their <code>FallbacksController#show</code> action.</p>\n\n<p>For example, if we decide that some subset of pages should be rendered in some\nother way:</p>\n\n<pre><code>class FallbacksController &lt; ApplicationController\n  JEANS_SECTION = \"/unisex/jeans\"\n  TOPS_SECTION = /unisex/tops\"\n\n  rescue_from ActiveRecord::RecordNotFound, with: :render_404\n\n  def show\n    path = params[:path]\n\n    # If a page with the given path cannot be found, `#find_by!`\n    # raises an `ActiveRecord::RecordNotFound` exception.\n    @page = Page.find_by!(path: params[:path])\n\n    if path.starts_with? JEANS_SECTION\n      render \"jeans_listing\"\n    elsif path.starts_with? TOPS_SECTION\n      render \"tops_listing\"\n    else\n      render \"show\"\n    end\n  end\nend\n</code></pre>\n\n<p>Now, even though we are rendering three different templates, our only dependency\nis a <code>@page</code> record. In this example controller action, the code indicates that\nour pages are basically all the same but can now be presented in three different\nways. In my opinion that’s an acceptable amount of complexity.</p>\n\n<p>But this can get out of hand fast if we want other variations of the product\nlisting pages, or tack on other pages that require a top-level route like\n<code>/about</code> or <code>/contact</code>:</p>\n\n<pre><code>class FallbacksController &lt; ApplicationController\n  GRAVEYARD_CATEGORY = \"graveyard\"\n\n  JEANS_SECTION = \"/unisex/jeans\"\n  TOPS_SECTION = /unisex/tops\"\n\n  STATIC_PAGES = [\"/about\", \"/contact\"]\n\n  rescue_from ActiveRecord::RecordNotFound, with: :render_404\n\n  def show\n    path = params[:path]\n\n    # If a page with the given path cannot be found, `#find_by!`\n    # raises an `ActiveRecord::RecordNotFound` exception.\n    @page = Page.find_by!(path: params[:path])\n\n    # Only include products that have been discontinued.\n    @products =\n      if path.includes?(GRAVEYARD_CATEGORY)\n        Product.where(discontinued_at: ..Time.now, taxons: @page.taxons)\n      else\n        Product.where(taxons: @page.taxons)\n      end\n\n    render_404 and return if (@products.none? &amp;&amp; !STATIC_PAGES.include?(path))\n\n    if STATIC_PAGES.include?(path)\n      render \"static_page\"\n    elsif path.starts_with? JEANS_SECTION\n      render \"jeans_listing\"\n    elsif path.starts_with? TOPS_SECTION\n      render \"tops_listing\"\n    else\n      render \"show\"\n    end\n  end\nend\n</code></pre>\n\n<p>So here we’ve added a lot of functionality to <code>FallbacksController#show</code>.</p>\n\n<ul>\n  <li>the rendering of static pages</li>\n  <li>the rendering of a “product graveyard” for collections of discontinued products</li>\n  <li>the rendering of a 404 page if a collection of <code>@products</code> happens to be empty\nand we’re not trying to render a static page like <code>/about</code>.</li>\n</ul>\n\n<p>Obviously this is a bit contrived; if we actually needed to render all of these\npages from a single controller action, we might restructure it a bit. But\nhopefully this highlights the fact that… this should have always been served\nby many controllers.</p>\n\n<p>Using typical Rails routes, undoing this technical debt could be a considerable\namount of work, though, if we don’t want to break the existing routing. And, of\ncourse, maybe we do have requirements for static pages like the about page: that\nthey are served via <code>/about</code> rather than <code>/some-controller-prefix/about</code>.</p>\n\n<h2 id=\"reducing-complexity-using-routing-constraints\">Reducing complexity using routing constraints</h2>\n\n<p>The least-effort way around the controller action stuffing would be use <a href=\"https://guides.rubyonrails.org/routing.html#advanced-constraints\">routing\ncontraints</a>, which allows us to stop stuffing\nall of this complexity into a single controller action. You can express this\neither as a lamdba or as a class that adheres to <a href=\"https://github.com/rails/rails/blob/v8.0.0/actionpack/lib/action_dispatch/routing/mapper.rb#L29\">Rails’s contraints API</a>:</p>\n\n<pre><code>class PageConstraints\n  # Matches page paths. To be really nice, we'll optionally account for a\n  # slash at the beginning and/or end of the request path. i.e. `about`,\n  # `/about`, `about/`, or `/about/`.\n  PAGE_PATH_REGEXP = %r{\\A/?[^/]*/?\\z}\n\n  def matches?(request) = request.path.match?(PAGE_PATH_REGEXP)\nend\n\nclass GraveyardCategoryConstraints\n  GRAVEYARD_CATEGORY_KEYWORD = \"graveyard\"\n\n  def matches?(request)\n    request.path.match? %r{.+#{GRAVEYARD_CATEGORY_KEYWORD}.*}\n  end\nend\n\nRails.application.routes.draw do\n  resources :posts\n  resources :users\n\n  # Example using a custom constraints lambda.\n  get \"/*path\",\n    contraints: -&gt;(request) {\n      request.path.match?(Product.known_category_prefixes)\n    },\n    to: \"products#show\"\n\n  # Example using a custom constraints class.\n  constraints GraveyardCategoryConstraints.new do\n    get \"/*path\", to: \"graveyard_products#show\"\n  end\n\n  # Example using a custom constraints class.\n  contraints PageConstraints.new do\n    get \"/*path\", to: \"pages#show\"\n  end\n\n  # Aaaaaannd the old fallback route.\n  get \"/*path\", to: \"fallbacks#show\"\nend\n</code></pre>\n\n<p>I won’t include example code for all of the individual controllers, but I hope\nyou can see how splitting the single, monolithic <code>FallbacksController#show</code>\naction into four separate controllers would make each of the actions much more\nmaintainable.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/see-you-at-euruko-2025","url":"https://benjaminwil.info/weblog/see-you-at-euruko-2025","external_url":null,"title":"See you at EuRuKo 2025","summary":"I’ll be at EuRuKo, the European Ruby conference, in Viana do Castelo, Portugal, this month.","image":null,"banner_image":null,"date_published":"2025-09-09 12:15:46 -0700","date_modified":"2025-09-09 12:15:46 -0700","tags":[],"language":"en","content_html":"<p>I’ll be at <a href=\"https://2025.euruko.org/\">EuRuKo</a>, the European Ruby conference, in\nViana do Castelo, Portugal, this month. Maybe I’ll see you there? We could grab\na coffee.</p>\n"},{"id":"https://benjaminwil.info/weblog/typesetting-album-artist-separation","url":"https://benjaminwil.info/weblog/typesetting-album-artist-separation","external_url":null,"title":"Typesetting artist name–album title separation","summary":"Recently I’ve had two occasions to think about how to typeset musical artist names when next to their album release names...","image":null,"banner_image":null,"date_published":"2025-07-30 11:54:45 -0700","date_modified":"2025-07-30 11:54:45 -0700","tags":[],"language":"en","content_html":"<p>Recently I’ve had two occasions to think about how to typeset musical artist\nnames when next to their album release names. I couldn’t find a very\nauthoritative source on the subject, so I’ll offer up my own findings.</p>\n\n<p>For music-related documents and user interfaces, you may sometimes need display\nan artist and album title next to each other. What are reasonable choices for\nseparators? Publications like Pitchfork and applications like Bandcamp, Spotify,\nand Tidal try to side-step this issue by avoiding interface components where\nthese two elements are displayed next to each other.  They instead prefer to put\none above the other on separate lines. That’s a reasonable solution, but let’s\npretend it’s a luxury we don’t have.</p>\n\n<p>Maybe the simplest solution would be to use different font styles for the artist\nand album:</p>\n\n<blockquote>\n  <p>\n    <strong aria-label=\"Artist name\">Lizzy Mercier Desclaux</strong>\n    <span aria-label=\"Album name\">Mambo Nassau</span>\n  </p>\n</blockquote>\n\n<p>Let’s pretend we don’t have this luxury and that we must reach for typesetting\nseparator-characters.</p>\n\n<p>If we want to optimize for easy authorship, we could use colons:</p>\n\n<blockquote>\n  <p>Lizzy Mercier Desclaux: Mambo Nassau</p>\n</blockquote>\n\n<p>However, colons sometimes appear in album titles. Especially if you’re attempting\nto present artist and album titles across many or all musical genres, this might\nnot be the best choice. For some genres, like classical and contemporary art\nmusic recordings, colons might even create ambiguity (or readability issues)\nabout which part is the album and which part is the artist:</p>\n\n<blockquote>\n  <p>Chen Pi-Hsien: Messiaen: 20 Regards sur l’Enfant-Jésus, I-27</p>\n</blockquote>\n\n<p>There are other simple separators like commas and slashes that share this\nambiguity problem. So we want to optimize for disambiguation, using an en- or\nem-dash seems to be safer, at least for now, in 2025:</p>\n\n<blockquote>\n  <p>Lizzy Mercier Desclaux – Mambo Nassau</p>\n</blockquote>\n\n<blockquote>\n  <p>Chen Pi-Hsien – Messiaen: 20 Regards sur l’Enfant-Jésus, I-27</p>\n</blockquote>\n\n<p>Using dashes is also good enough for NME, iTunes, Apple Music, and Discogs to\nseparate artist names from album titles, if that means anything to you. It does\nto me. Except in situations where sub-pixel real estate matters, dashes look\ngood, are good disambiguators, and should be renderable by any font that’s any\ngood.</p>\n\n<p>If you’re considering using a hyphen instead of a dash: please don’t. Hyphens\nfrequently appear in human names and album titles, and would not be a good\nseparator or a smart disambiguator. I’ll admit that even dashes are an unusual\nseparator character. But since they appear so infrequently in this context,\nthey’re a shoo-in. For more information about the difference between hyphens,\nen-dashes, and em-dashes, I recommend <a href=\"https://practicaltypography.com/hyphens-and-dashes.html\">the Butterick’s Practical Typography\narticle about hyphens and\ndashes</a>.</p>\n"},{"id":"https://benjaminwil.info/weblog/github-discussions-suck","url":"https://benjaminwil.info/weblog/github-discussions-suck","external_url":null,"title":"GitHub Discussions is modelled poorly for open-ended conversations","summary":"Note that this article criticizes GitHub’s Discussions feature (originally launched in 2017) as it exists now, in July 20...","image":null,"banner_image":null,"date_published":"2025-07-22 20:12:56 -0700","date_modified":"2025-07-22 20:12:56 -0700","tags":[],"language":"en","content_html":"<p><em>Note that this article criticizes GitHub’s Discussions feature (originally\nlaunched in 2017) as it exists now, in July 2025.</em></p>\n\n<p>In case you don’t know, <a href=\"https://docs.github.com/discussions\">Discussions</a> is\nGitHub’s answer to forums and <a href=\"https://stackoverflow.com/questions\">Stack\nOverflow</a>-style Q&amp;As. Users can reply to an\ninitial message in a discussion and upvote, downvote, or comment on any response.\nIn addition to announcement threads and polls, discussions can either be\n<strong>open-ended discussions</strong> or <strong>question/answer discussions</strong>.</p>\n\n<p>Question/answer discussions:</p>\n\n<ul>\n  <li>can be viewed in one of a few sort orders (top voted first; newest first; oldest first) and</li>\n  <li>can have a single response marked as “the answer” to the discussion.</li>\n</ul>\n\n<p>Open-ended discussions:</p>\n\n<ul>\n  <li>can also be viewed in one of a few sort orders (top voted first; newest first; oldest first) and</li>\n  <li>do not have any response marked as “the answer.”</li>\n</ul>\n\n<p>The Q&amp;A discussions improve upon the Stack Overflow model in an important way:\nthe project itself is the owner of the discussion board. That means that project\nadministrators are hypothetically present, moderating conversations and\ncorrecting potential mis/disinformation.</p>\n\n<h2 id=\"user-interface-deficiencies\">User interface deficiencies</h2>\n\n<p>Unfortunately, unlike the Q&amp;A discussions, the open-ended discussions feature is\nan afterthought in comparison.  Even visually, responses to open-ended\ndiscussions look disconnected from one another. Each response is an island,\nwith borders, primed for its own disparate comments thread.</p>\n\n<figure>\n  <a target=\"_blank\" href=\"/weblog/assets/github-discussions-suck/thread-comparisons-discourse-discussions-issues.png\">\n    <img src=\"/weblog/assets/github-discussions-suck/thread-comparisons-discourse-discussions-issues@0.5.png\" alt=\"Side by side, comments on a Discourse thread, comments on a GitHub discussion, and comments on a GitHub issue, showcasing the user interface of each document.\" />\n  </a>\n  <figcaption>\n    <p>\n      From left to right: comments on Discourse conversation, a GitHub discussion,\n      and a GitHub issue. Of the three, the GitHub discussion stands out as having\n      a visible textarea with placeholder text \"Write a reply\" between two\n      messages meant to be read as replies to each other. It also stands out as\n      visually separating the messages from each other. This design\n      indicates that this isn't a discussion: it's meant to be listing of\n      threads.\n    </p>\n\n    <p>\n      You might have noticed that the Discourse thread I captured actually contains a\n      reply to an earlier message in the thread not shown here. This is a bit\n      complicated, but regardless, the thread is still displayed in chronological\n      message order.\n    </p>\n  </figcaption>\n</figure>\n\n<p>While Discourse threads and GitHub issues both have their own user interface\nchallenges and deficiencies, issues are displayed more like I would personally\nexpect open-ended discussions to be displayed: a single conversation, without\nnested comments, and visually each message in the issue is linked to indicate a\nchronology. Interestingly, issues can be converted into discussions by project\nadministrators–but not the other way around (for reasonable complexity-related\nreasons, I’m sure), though admins can create an issue <em>from</em> a discussion.</p>\n\n<p>As a GitHub repository administrator, you must configure Discussions and the\nproject’s enabled discussion categories. Each category will allow for\ndiscussions of one type (announcements; polls; Q&amp;As; open-ended discussions).\nWhen creating a new discussion category, the default selected mode is\n<strong>question/answer</strong>. In my experience, this really shows.  For example, see\n<a href=\"https://github.com/laravel/framework/discussions/categories/show-and-tell\">Laravel’s “Show and Tell” discussion\ncategory</a>,\nwhich contains hundreds of “unanswered” links and plugs that members of the\nLaravel community may find relevant. No offence to anyone (I’m not a member\nof the Laravel community), but calling these “unanswered” feels like a\nmistake. Given this example, and the visual design of the discussion page, it\nseems clear that GitHub’s designers prioritized the functionality\nof the Q&amp;A-style discussions.</p>\n\n<p>All four discussion types have the exact same threading system, well-suited to\nStack Overflow-like Q&amp;As, and less well-suited for announcements made by project\nmaintainers and open-ended discussions.  For all four discussion types,\nresponses can be upvoted individually and have their own nested comments\nthreads. This specifically makes having an open-ended discussion quite complex:\nopen-ended discussions are now not just open-ended, but also achronological,\nnon-linear, or single-threaded, depending on how nested comments are (ab)used.</p>\n\n<h2 id=\"de-linearizing-conversations\">De-linearizing conversations</h2>\n\n<p>Years ago, I started <a href=\"https://github.com/orgs/solidusio/discussions/4634\">a discussion on the Solidus\nproject</a> to have an\nopen-ended discussion about how to handle a particular issue I was facing\nintegrating with the Solidus framework’s provided frontend templates. There was\nno need for upvotes (or downvotes, thankfully), but all responders ended up\ncommenting on a single response to the thread. The shape of this discussion\nwould have been better suited to a single, flat thread, i.e.:</p>\n\n<pre><code># original post -&gt; [responses]\n\nOriginal Poster   \"Hi, this is a question or comment about The Project.\"\nResponder 1       └── \"Hi, this is a response to the question or comment.\"\nResponder 2       └── \"Hi, this is also a response to the question or comment, but I'm also in conversation with Responder 1, who responded before me.\"\n</code></pre>\n\n<p>rather than the tree structure it ended up as due to the GitHub Discussion’s design\nchoices:</p>\n\n<pre><code># original post -&gt; [response -&gt; [comments]]\n\nOriginal Poster   \"Hi, this is a question or comment about The Project.\"\nResponder 1       └── \"Hi, this is a response to the question or comment.\"\nResponder 2           └── \"Hi, this is also a response to the question or comment, but I'm also in conversation with Responder 1, who responded before me.\"\n</code></pre>\n\n<p>The tree structure makes the otherwise-linear conversation full of potential for\nnon-linearity and complexity. After all, this is purportedly a single discussion.\nImagine what this simple, linear conversation would look like with ten, or\nfifty, more participants.</p>\n\n<p>Perhaps my discussion should have actually been a <a href=\"https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues\">GitHub\nissue</a>\nto begin with. Or, maybe, a message from the discussion should have been used as\nthe source for a new issue. Well, it doesn’t matter. This discussion has long\nbeen abandoned and no action has been directly taken as the result of it. It’s\nmeaningful that issues imply actionability and discussions do not, but I find it\ntroubling that issues prioritize the chronology and linearity of a conversation\nwhile GitHub’s open-ended discussions don’t.</p>\n\n<p>GitHub’s <a href=\"https://github.blog/open-source/maintainers/create-a-home-for-your-community-with-github-discussions/\">announcement blog post for Discussions</a> describes the feature as\n“dedicated space for conversations,” and now, years later, that still feels\nuntrue as I attempt to use these features or read past discussions.\nIt also describes the feature as a way to “create a home for your community,”\ndespite most discussion boards I’ve seen more closely resembling a community\nsupport, Stack Overflow-like Q&amp;A feed.</p>\n\n<h2 id=\"just-using-it-wrong\">“Just using it wrong”</h2>\n\n<p>There is a place for nested conversations. I don’t think the GitHub discussion I\nstarted is one of them. The nested response-comments makes the conversation look\nlike the first responder’s comment is <em>more important</em> than the following\ncomments. The structure and styles of the HTML document tell that story, too.\nAny discussion-readers not participating or reading closely might not understand\nthat all of these messages are in response to the original discussion message\nequally.</p>\n\n<p>You could minimize this by saying discussion participants are not using\nDiscussions “properly.” Hm, but should a responder have to think that hard about\nwhether to respond or comment on a response? Should they have to make this worse\nby accepting a previous commenter or responder’s decision to “use the feature\nwrong”? In the world of Stack Overflow-like Q&amp;As, this complexity makes sense.\nFor an “open-ended discussion” it does not.</p>\n\n<p>GitHub’s own documentation about <a href=\"https://docs.github.com/en/discussions/collaborating-with-your-community-using-discussions/participating-in-a-discussion#about-participation-in-a-discussion\">how to participate in a\ndiscussion</a>\nis quite complex:</p>\n\n<blockquote>\n  <ul>\n    <li>Comment in response to the original comment from the author of the discussion</li>\n    <li>Create a comment thread by replying to an individual comment that another\ncommunity member made within the discussion\n<br />…</li>\n    <li>Upvote discussions and top-level comments to give them more visibility</li>\n  </ul>\n</blockquote>\n\n<p>As a way to describe the critical functionality of a message board, these\nparticipation instructions seem complex.  Unfortunately, you can’t just say\n“reply to a thread,” or “contribute a message to the conversation,” because\nthese things aren’t really conversations.</p>\n\n<p>I don’t have much more to say about this other than I don’t think Discussions\nis a good form factor for most real, meaningful discussions, and they\ndefinitely aren’t good at being the primary forum for conversations being had by\nserious free and/or open-source software projects.</p>\n"},{"id":"https://benjaminwil.info/weblog/no-screenshots","url":"https://benjaminwil.info/weblog/no-screenshots","external_url":null,"title":"Prefer text over screenshots","summary":"If you want me to read some text, use your computer’s text-copy commands to provide me with the data rather than taking a...","image":null,"banner_image":null,"date_published":"2025-05-07 21:02:46 -0700","date_modified":"2025-05-07 21:02:46 -0700","tags":["#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>If you want me to read some text, use your computer’s text-copy commands to\nprovide me with the data rather than taking a screenshot. There are a lot of\ngood reasons to do this.</p>\n\n<h2 id=\"screen-size-variability\">Screen size variability</h2>\n\n<p>The sender won’t always know how to format a screenshot so the receiver can read\nit easily. I’m sure that you, too, have pinch-zoomed your way across a wide\nimage on a narrow touchscreen. Pinch-zooming your way across a wide image filled\nwith text can make reading a slow and error-prone process.</p>\n\n<h2 id=\"reliability-and-rediscoverability\">Reliability and rediscoverability</h2>\n\n<p>Raw text content will always be more searchable than images. This allows you and\nothers to rediscover the text when it is useful again later on.</p>\n\n<p>I know that OCR exists and text can be extracted from images and videos in an\nautomated way now. Unfortunately, I know too well that OCR is lossy and can even\nproduce text with comprehensive typos. So, searching for text content from OCRed\nimages cannot be as reliable as raw text content. Yes, even if you throw an LLM\nin at the end to help normalize the OCRed text.</p>\n\n<h2 id=\"text-can-be-translated\">Text can be translated</h2>\n\n<p>It’s true that raw text and OCRed text can both be translated into other\nlanguages. But I’d always feel more confident throwing the raw text into\ntranslation software for the reasons given in my previous point.</p>\n\n<h2 id=\"text-can-be-transformed\">Text can be transformed</h2>\n\n<p>If you want me to read some text, you may also want me to decode, decant, or\nedit the raw text.</p>\n\n<p>Without any specialized software, our computers are still good at text\nediting. Being able to copy text from one application and paste it in another\nis beyond convenient. Not only can you transform the text content, you\ncan transform its display to better see or make sense of it.</p>\n\n<p>Without any specialized software, our computers are not great at duping, editing,\nor processing image content. Having to manually re-copy text from an image or\nvideo is less efficient.</p>\n\n<h2 id=\"text-is-portable\">Text is portable</h2>\n\n<p>Going a bit deeper on that last point: text is more portable than an image. Text\ntakes up less disk space, can be trivially opened by many softwares on many\nsystems. Text can be printed out on even the most rudimentary of printers.</p>\n\n<h2 id=\"why\">Why?</h2>\n\n<p>As a software developer, I often participate in message threads in which someone\nwants to discuss a piece of code or documentation, or a shapeless stack of log\nmessages. Some senders would post a screenshot containing a representation of\nthe text rather than the raw text. I never enjoy this, especially when I’m\nreading from my phone.</p>\n\n<p>There may be real reasons they did this:</p>\n\n<ul>\n  <li>The software being used makes it too difficult to reliably select text\n(cheers, iOS).</li>\n  <li>The software being used makes it too difficult to copy text (cheers, Tmux).</li>\n</ul>\n\n<p>For anyone with these reasons, I recommend finding other software that allows\nyou to more easily select and copy text. Or, I recommend learning the\ndifficult-to-use software’s select- and copy-commands. Or, as a last resort, I\nrecommend recopying manually the text content you wish to send me.</p>\n\n<p>You may be the sender and the text’s secondary reader for now, but in the future\nyou may be the text’s primary reader. Make reading the text easier for yourself.</p>\n"},{"id":"https://benjaminwil.info/weblog/the-shrouds-2024","url":"https://benjaminwil.info/weblog/the-shrouds-2024","external_url":null,"title":"The Shrouds (2024)","summary":"In one of the first scenes, Karsh explains to a date that the GraveTech cemetery he built, where Becca, his Jewish wife, ...","image":null,"banner_image":null,"date_published":"2025-04-30 00:00:00 +0000","date_modified":"2025-04-30 00:00:00 +0000","tags":["#<Lifer::Tag:0x00007fffdb586e10>","#<Lifer::Tag:0x00007fffdb70d630>"],"language":"en","content_html":"<p>In one of the first scenes, Karsh explains to a date that the GraveTech\ncemetery he built, where Becca, his Jewish wife, is buried, is a\n“non-denominational” grounds. This isn’t quite the right word considering the\ninter-faith inhabitants of the cemetery. Karsh, a gentile, says that in the\nend he’ll be buried there, next to Becca. This is not the last time in <em>The\nShrouds</em> that Karsh will use an exact, but incorrect, word. As a tech founder,\nit’d be normal for Karsh to misfield words. Many people with CEO-brain are\nnaive to a fault and put boundless trust in the specialists around them. Karsh\ndelegates to his dead wife’s sister’s specialist ex-husband Maury so that\nhe can sleep, drive around in his Tesla, and emote.</p>\n\n<p>It’d also be normal for the specialists and executive-types around him to use\nthe wrong words. And they do, unless in this near-future Canada it’s accurate\nto call one’s AI personal assistant their “avatar.” An avatar is meant to be a\nrepresentation of one’s self. Karsh has no avatar in the film. Although Karsh’s\npersonal assistant Hunny represents him in video calls, she is importantly\nnot Karsh, but a Memoji-esque representation of his late wife created by Maury.</p>\n\n<p>I’m inclined to attribute the wrongful usage of the word “avatar” to\nthe writer-director, who has an immaculate history of making the holiest\nvibes-based cinema. He need not care whether he gets things a little wrong,\nand his work is often more interesting because of what he gets wrong. Then,\nmaybe he also means to say that after death, the manifestation of our loved\nones say more about us than anyone else. We have Cronenberg on record saying\nthat <em>The Shrouds</em> is “autobiographical,” inspired by the loss of his wife\nCarolyn. So Karsh is the avatar, a Cronenberg stand-in, and the Director-Artist\nwho keeps the distorted love-memories alive through his own flawed creations.</p>\n"},{"id":"https://benjaminwil.info/weblog/atom-vs-rss","url":"https://benjaminwil.info/weblog/atom-vs-rss","external_url":null,"title":"Atom vs. RSS","summary":"While working on my static site generator, Lifer, I was occasionally annoyed by how my test feeds were being read by RSS ...","image":null,"banner_image":null,"date_published":"2025-04-05 10:41:32 -0700","date_modified":"2025-04-05 10:41:32 -0700","tags":["#<Lifer::Tag:0x00007fffdb5603a0>","#<Lifer::Tag:0x00007fffdb7b1118>"],"language":"en","content_html":"<p>While working on my static site generator,\n<a href=\"https://github.com/benjaminwil/lifer\">Lifer</a>, I was occasionally annoyed by how\nmy test feeds were being read by RSS feed readers. And I was occasionally\nannoyed at the <code>rss</code> Ruby gem source code for generating XML tags in my feeds\nthat I wasn’t explicitly specifying. Chris Wellons’s <a href=\"https://nullprogram.com/blog/2013/09/23/\">Atom vs. RSS</a> blog\npost expresses the same feelings of surprise I felt when digging deeper into the\nancient history that is the Atom and RSS 2.0 specifications.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/ported-to-lifer","url":"https://benjaminwil.info/weblog/ported-to-lifer","external_url":null,"title":"This website has been ported to Lifer 0.9","summary":"Since releasing Lifer 0.3 in January I’ve released six more minor versions to get the project stable enough to start usin...","image":null,"banner_image":null,"date_published":"2025-04-05 10:03:19 -0700","date_modified":"2025-04-05 10:03:19 -0700","tags":["#<Lifer::Tag:0x00007fffdb56acb0>","#<Lifer::Tag:0x00007fffdb7130f8>"],"language":"en","content_html":"<p>Since releasing <a href=\"/weblog/lifer-0-3/\">Lifer 0.3 in January</a> I’ve released six\nmore minor versions to get the project stable enough to start using. <a href=\"https://github.com/benjaminwil/lifer/blob/v0.9.0/CHANGELOG.md\">The\nchangelog entries</a> don’t make the releases sound that interesting,\nbut as an end user I’m much happier with the build performance, the tag support,\nand Lifer’s awareness of original publication <em>and</em> last updated dates.</p>\n\n<div class=\"feed-only\">\n  <small> Note to readers subscribed via a newsfeed: sorry if the feed has\n  spammed you with new entries spanning the many years of this blog's existence.\n  My Jekyll feed's settings were bad, and it seemed not worth it to me to make\n  the feed's transition any more graceful. </small>\n</div>\n\n<p>benjaminwil.info looks and feels the same way it always did, but it’s no longer\nbeing generated by <a href=\"https://jekyllrb.com\">Jekyll</a>–but by Lifer. There’s still\nplenty to do before I could cut a v1.</p>\n\n<p>Lifer definitely has swerved out of the <em>Jekyll clone</em> lane into the <em>could be a\ngood and unique site generator someday</em> lane, and I’m excited about some upcoming\nfeatures that make it even more flexible for people who are willing to commit\na bit of Ruby to their site repository.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/for-rails-newbies","url":"https://benjaminwil.info/weblog/for-rails-newbies","external_url":null,"title":"From developer to Rails developer","summary":"In 2023, I wrote this guide to getting familiar with Ruby and Rails for my employer, Super Good Software.","image":null,"banner_image":null,"date_published":"2025-02-11 09:00:00 -0700","date_modified":"2025-02-11 09:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>In 2023, I wrote <a href=\"https://supergood.software/from-developer-to-rails-developer-and-then-some/\">this guide to getting familiar with Ruby and Rails</a> for my\nemployer, <a href=\"https://super.gd\">Super Good Software</a>. In 2025, I wouldn’t change\nmuch too much about this article, which, I think, is a testiment to how mature\nand <em>developer experience-focused</em> the Ruby and Rails ecosystems are.</p>\n\n<p>But I would stop recommending <a href=\"https://pry.github.io/\">the Pry REPL</a> now. In\n2025, even the oldest supported version of Ruby now includes an enhanced IRB\nthat provides many of the features I used to depend on Pry for. One can simply\ninstall <a href=\"https://github.com/ruby/debug\">the <code>debug</code> gem</a> to get even more\nPry-like behaviours from IRB.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/lifer-0-3","url":"https://benjaminwil.info/weblog/lifer-0-3","external_url":null,"title":"Lifer 0.3","summary":"I recently released 0.3.0 of my static site generator project Lifer, which I intend to use to build this website in the (...","image":null,"banner_image":null,"date_published":"2025-01-05 13:14:00 -0700","date_modified":"2025-01-05 13:14:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb56acb0>","#<Lifer::Tag:0x00007fffdb7130f8>"],"language":"en","content_html":"<p>I recently released 0.3.0 of my static site generator project\n<a href=\"https://github.com/benjaminwil/lifer\">Lifer</a>, which I intend to use to build\nthis website in the (near) future. Right now, I build this website using\n<a href=\"https://jekyllrb.com\">Jekyll</a>, the “simple, blog-aware” static site generator.</p>\n\n<p>Lifer and Jekyll have some things in common. For example, they’re both written\nin Ruby, and they both output HTML documents and RSS feeds to an output\ndirectory. They both read frontmatter metadata from Markdown files to help you\nmaintain collections of pages and blog posts that belong to a small- or\nmedium-sized website.</p>\n\n<p>Jekyll has done me no wrong, but there are things about Jekyll I have found\nopinionated or hard to work around: Jekyll requires you to use Liquid templates\nfor generating posts and pages; <code>_posts</code> is a bit too magic a collection of\narticles; its built-in asset pipeline is not very flexible.</p>\n\n<p>It seemed like a good opportunity for me to try designing my own site generator,\nto see how simple I could make something I could use for myself, and to learn\nfirst-hand where all of the hidden complexity lies.</p>\n\n<p>Now, 150-ish commits in, the shape of the site generator I want is coming\ntogether. I started this project, casually, over two years ago. So, at this\nrate, it’ll be a long time before anyone else can actually use Lifer. Testing\nthe generator in production, though, will be quite a milestone. Stay tuned.</p>\n"},{"id":"https://benjaminwil.info/weblog/2024-film","url":"https://benjaminwil.info/weblog/2024-film","external_url":null,"title":"The best films I saw: 2024 edition","summary":"In no particular order, here’s my annual list of the movies I loved that I saw for the first time in 2024.","image":null,"banner_image":null,"date_published":"2024-12-31 12:00:00 -0700","date_modified":"2024-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>In no particular order, here’s my annual list of the movies I loved that I saw\nfor the first time in 2024. This year, I included two limited series as entries,\nwhich is a bit unusual of me. This list is also <a href=\"https://letterboxd.com/benjaminwil/list/top-thirty-2024/\">published on\nLetterboxd</a>.</p>\n\n<p>Here’s links to my previous years’s lists: <a href=\"/weblog/2023-film\">2023</a>,\n<a href=\"/weblog/2022-film\">2022</a>, <a href=\"/weblog/2021-film\">2021</a>, <a href=\"/weblog/2020-film\">2020</a>,\n<a href=\"/weblog/2019-film\">2019</a>, <a href=\"/weblog/2018-film\">2018</a>, <a href=\"/weblog/2017-film\">2017</a>.</p>\n\n<p>This year’s list:</p>\n\n<ul>\n  <li>Hong Sang-soo: <em>The Woman Who Ran</em>, 2020</li>\n  <li>William Friedkin: <em>The Caine Mutiny Court-Martial</em>, 2023</li>\n  <li>Théo Jollet: <em>Meet Doug</em>, 2021</li>\n  <li>Hong Sang-soo: <em>Nobody’s Daughter Haewon</em>, 2013</li>\n  <li>Tsai Ming-liang: <em><a href=\"https://www.filmcomment.com/blog/film-of-the-week-rebels-of-the-neon-god/\">Rebels of the Neon God</a></em>, 1992</li>\n  <li>Ryûsuke Hamaguchi: <em><a href=\"https://www.newyorker.com/culture/the-current-cinema/the-beautifully-unnerving-gaze-of-evil-does-not-exist\">Evil Does Not Exist</a></em>, 2023</li>\n  <li>Robert Altman: <em>The Player</em>, 1992</li>\n  <li>Paul Schrader: <em>Hardcore</em>, 1979</li>\n  <li>Luca Guadagnino: <em>Challengers</em>, 2024</li>\n  <li>Harris Mayersohn: <em>Stand Up Solutions</em>, 2024</li>\n  <li>Bernard Rose: <em><a href=\"https://www.rogerebert.com/reviews/ivans-xtc-2002\">ivans xtc.</a></em>, 2000</li>\n  <li>Albert Serra: <em>Pacifiction</em>, 2022</li>\n  <li>Léa Mysius: <em>The Five Devils</em>, 2022</li>\n  <li>Bill Ross IV &amp; Turner Ross: <em><a href=\"https://www.voxmagazine.com/arts/45365-true-false-2020/article_a02b0d76-5f33-11ea-ace0-937f6e7a9225.html\">45365</a></em>, 2009</li>\n  <li>Bill Ross IV &amp; Turner Ross: <em>Tchoupitoulas</em>, 2012</li>\n  <li>Abbas Kiarostami: <em>Where Is the Friend’s House?</em>, 1987</li>\n  <li>Paolo Sorrentino: <em>The New Pope</em>, 2020</li>\n  <li>Elaine May: <em><a href=\"https://www.newyorker.com/goings-on-about-town/movies/mikey-and-nicky-2\">Mikey and Nicky</a></em>, 1976</li>\n  <li>Krzysztof Kieślowski: <em>Three Colours: Blue</em>, 1993</li>\n  <li>Éric Rohmer: <em>A Tale of Springtime</em>, 1990</li>\n  <li>Matthew Rankin: <em><a href=\"https://www.bfi.org.uk/sight-and-sound/reviews/universal-language-beautifully-absurd-crosscultural-odyssey\">Universal Language</a></em>, 2024</li>\n  <li>Miguel Gomes : <em><a href=\"https://mubi.com/en/notebook/posts/all-is-full-of-grace-miguel-gomes-on-grand-tour\">Grand Tour</a></em>, 2024</li>\n  <li>Sean Baker: <em>Anora</em>, 2024</li>\n  <li>Francis Ford Coppola: <em>Megalopolis</em>, 2024</li>\n  <li>Ira Sachs: <em>Forty Shades of Blue</em>, 2005</li>\n  <li>Payal Kapadia: <em><a href=\"https://roughcutfilm.com/2024/08/21/review-all-we-imagine-as-light-is-a-stunning-tale-of-intimacy-as-dissent/\">All We Imagine as Light</a></em>, 2024</li>\n  <li>Steven Zaillian: <em>Ripley</em>, 2024</li>\n  <li>Krzysztof Kieślowski: <em>Three Colours: White</em>, 1994</li>\n  <li>Hong Sang-soo: <em><a href=\"https://www.criterion.com/current/posts/7406-hong-sangsoo-s-tale-of-cinema\">Tale of Cinema</a></em>, 2005</li>\n  <li>Wim Wenders: <em>Perfect Days</em>, 2023</li>\n</ul>\n"},{"id":"https://benjaminwil.info/weblog/2023-film","url":"https://benjaminwil.info/weblog/2023-film","external_url":null,"title":"The best films I saw: 2023 edition","summary":"As usual: here’s my annual list of the thirty best movies I watched for the first time this year.","image":null,"banner_image":null,"date_published":"2023-12-31 12:00:00 -0700","date_modified":"2023-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>As usual: here’s my annual list of the thirty best movies I watched for the\nfirst time this year. In no particular order. I also publish it <a href=\"https://letterboxd.com/benjaminwil/list/top-thirty-2023/\">on\nLetterboxd</a>.</p>\n\n<p>I’ve been doing this for a while now, so here are some convenience links to\nprevious lists: <a href=\"/weblog/2022-film\">2022</a>, <a href=\"/weblog/2021-film\">2021</a>,\n<a href=\"/weblog/2020-film\">2020</a>, <a href=\"/weblog/2019-film\">2019</a>, <a href=\"/weblog/2018-film\">2018</a>,\n<a href=\"/weblog/2017-film\">2017</a>.</p>\n\n<p>And now, the list:</p>\n\n<ul>\n  <li>Ryûsuke Hamaguchi: <em><a href=\"https://cinema-scope.com/features/brief-encounters-hamaguchi-ryusukes-wheel-of-fortune-and-fantasy/\">Wheel of Fortune and Fantasy</a></em>, 2021</li>\n  <li>Abel Ferrara: <em>Bad Lieutenant</em>, 1992</li>\n  <li>Sofia Coppola: <em>Priscilla</em>, 2023</li>\n  <li>Hal Hartley: <em>The Unbelievable Truth</em>, 1989</li>\n  <li>William Peter Blatty: <em>The Exorcist III</em>, 1990</li>\n  <li>Dustin Guy Defa: <a href=\"https://www.highonfilms.com/editing-2021-short-film-review-mubi/\"><em>Editing</em></a>, 2021</li>\n  <li>Hal Hartley: <a href=\"https://variety.com/2001/film/reviews/no-such-thing-1200468350/\"><em>No Such Thing</em></a>, 2001</li>\n  <li>Michael Haneke: <em>Funny Games</em>, 1997</li>\n  <li>George Miller: <em>Three Thousand Years of Longing</em>, 2022</li>\n  <li>Olivier Assayas: <em>Clouds of Sils Maria</em>, 2014</li>\n  <li>Abel Ferrara: <em>The Blackout</em>, 1997</li>\n  <li>Hong Sang-soo: <em>Claire’s Camera</em>, 2017</li>\n  <li>Abel Ferrara: <em>King of New York</em>, 1990</li>\n  <li>Jim Jarmusch: <em>Paterson</em>, 2016</li>\n  <li>Eugene Kotlyarenko: <em>A Wonderful Cloud</em>, 2015</li>\n  <li>Michael Haneke: <a href=\"https://deepfocusreview.com/definitives/cache/\"><em>Caché</em></a>, 2005</li>\n  <li>Kelly Reichardt: <em>First Cow</em>, 2019</li>\n  <li>Stanley Kubrick: <em>Barry Lyndon</em>, 1975</li>\n  <li>Ridley Scott: <em>The Last Duel</em>, 2021</li>\n  <li>Tsai Ming-liang: <em>The Skywalk Is Gone</em>, 2002</li>\n  <li>Larry Clark: <a href=\"https://i-d.vice.com/en/article/7kv7n9/bully-larry-clark-cast-interview\"><em>Bully</em></a>, 2001</li>\n  <li>Kelly Reichardt: <em>Showing Up</em>, 2022</li>\n  <li>Sebastián Silva: <a href=\"https://www.bfi.org.uk/sight-and-sound/reviews/rotting-sun-this-shapeshifting-queer-comedy-unsparing-its-barbs\"><em>Rotting in the Sun</em></a>, 2023</li>\n  <li>Michael Mann: <em>Thief</em>, 1981</li>\n  <li>George Sluizer: <em><a href=\"https://www.theringer.com/movies/2018/9/5/17819076/the-vanishing-streaming-movie-influence\">The Vanishing</a></em>, 1988</li>\n  <li>Tom Noonan: <em>What Happened Was…</em>, 1994</li>\n  <li>Janicza Bravo: <em>House Comes with a Bird</em>, 2022 <a href=\"https://www.miumiu.com/us/en/miumiu-club/womens-tales/womens-tales-23.html\">🎥</a></li>\n  <li>George Armitage: <em>Miami Blues</em>, 1990</li>\n  <li>Robert Altman: <em>3 Women</em>, 1977</li>\n  <li>John Patton Ford: <em>Emily the Criminal</em>, 2022</li>\n</ul>\n\n"},{"id":"https://benjaminwil.info/weblog/2022-film","url":"https://benjaminwil.info/weblog/2022-film","external_url":null,"title":"The best films I saw: 2022 edition","summary":"In 2022 I watched some movies for the first time, as I do every year.","image":null,"banner_image":null,"date_published":"2023-01-01 12:00:00 -0700","date_modified":"2023-01-01 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>In 2022 I watched some movies for the first time, as I do every year. And these\nare the thirty<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup> that were the best, most interesting, etc.:</p>\n\n<ul>\n  <li>Tsai Ming-liang: <em>Vive L’Amour</em>, 1994</li>\n  <li>Amalia Ulman: <em>El Planeta</em>, 2021</li>\n  <li>Pier Paolo Pasolini: <em>Teorema</em>, 1968</li>\n  <li>Spike Lee: <em>Jungle Fever</em>, 1991</li>\n  <li>Pier Paolo Pasolini, Vittorio De Sica, Luchino Visconti, Franco Rossi, Mauro Bolognini: <em>The Witches</em>, 1967</li>\n  <li>Mariano Llinás: <a href=\"https://en.wikipedia.org/wiki/La_Flor\"><em>La Flor</em></a>, 2018</li>\n  <li>David Cronenberg: <em>Crimes of the Future</em>, 2022</li>\n  <li>Radu Jude: <em>Bad Luck Banging or Loony Porn</em>, 2021</li>\n  <li>Akira Kurosawa: <em>Seven Samurai</em>, 1954</li>\n  <li>Sophy Romvari: <em>Grandma’s House</em>, 2018</li>\n  <li>Paul Thomas Anderson: <em>Licorice Pizza</em>, 2021</li>\n  <li>William Friedkin: <em>The French Connection</em>, 1971</li>\n  <li>S. S. Rajamouli: <em>RRR</em>, 2022</li>\n  <li>Shirley Clarke: <em>Portrait of Jason</em>, 1967</li>\n  <li>Joachim Trier: <em>The Worst Person in the World</em>, 2021</li>\n  <li>Rhayne Vermette: <a href=\"https://mubi.com/notebook/posts/an-impossible-being-rhayne-vermette-discusses-ste-anne\"><em>Ste. Anne</em></a>, 2021</li>\n  <li>Sofia Bohdanowicz: <em>Never Eat Alone</em>, 2016</li>\n  <li>Edgar Morin, Jean Rouch: <em>Chronicle of a Summer</em>, 1961</li>\n  <li>Jane Schoenbrun: <em>We’re All Going to the World’s Fair</em>, 2021</li>\n  <li>Steven Soderbergh: <em>Schizopolis</em>, 1996</li>\n  <li>Wendell B. Harris, Jr.: <a href=\"https://en.wikipedia.org/wiki/Chameleon_Street\"><em>Chameleon Street</em></a>, 1989</li>\n  <li>J. Lee Thompson: <em>Conquest of the Planet of the Apes</em>, 1972</li>\n  <li>Ti West: <em>Pearl</em>, 2022</li>\n  <li>Derek Jarman: <em>Blue</em>, 1993</li>\n  <li>Sofia Bohdanowicz: <a href=\"https://en.wikipedia.org/wiki/Maison_du_Bonheur\"><em>Maison du Bonheur</em></a>, 2017</li>\n</ul>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>I’m counting <a href=\"https://en.wikipedia.org/wiki/La_Flor\"><em>La Flor</em></a> as five movies because it’s 808 minutes long.\n  Each year I try to get to a list of thirty, and some years it’s hard to. And\n  this is one of those years. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/providence-rhode-island","url":"https://benjaminwil.info/weblog/providence-rhode-island","external_url":null,"title":"Providence, RI","summary":"I was in Providence, Rhode Island, for RubyConf Mini and had the opportunity to eat and drink at some amazing places.","image":null,"banner_image":null,"date_published":"2022-12-02 11:40:00 -0700","date_modified":"2022-12-02 11:40:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6ef298>","#<Lifer::Tag:0x00007fffdb6eed20>"],"language":"en","content_html":"<p>I was in Providence, Rhode Island, for <a href=\"/weblog/rubyconf-mini\">RubyConf Mini</a> and had the\nopportunity to eat and drink at some amazing places. If you’re going to\nvisit Providence, I can give you the following recommendations:</p>\n\n<ul>\n  <li><a href=\"https://oberlinrestaurant.com/\">Oberlin</a>: Well-executed (!!) restaurant and bar. Try the raw bar. Try\nthe pasta. Try the toast. Walk in early, or make a reservation.</li>\n  <li><a href=\"https://www.fortnightpvd.com/\">Fortnight</a>: Workers’s cooperative wine bar. Unpretentious. Cared\nfor. Excellent wine and amaros menu (especially for someone coming from the\nwest coast of Canada).</li>\n  <li><a href=\"https://havenbrothersmobile.com/\">Haven Brothers</a>: A long-time institution. Go inside to see how to\nfit a full kitchen inside a horse trailer, stay for a stupid hot dog.</li>\n  <li><a href=\"https://www.marcelinosboutiquebar.com/\">Marcelino’s</a>: An unusual hotel bar. Great mediterranean-inspired\ncocktail menu.</li>\n  <li><a href=\"https://www.eddybar.com/\">eddy</a>: Thoughtful collection of wine, spirits, cocktails, and\ncharcuterie. Definitely worth going here more than once.</li>\n  <li><a href=\"https://as220.org/\">AS220</a>: A non-profit arts centre with a bar and live events, with\nlots of history. <a href=\"https://en.wikipedia.org/wiki/AS220\">It’s got a Wikipedia page</a>.</li>\n  <li><a href=\"http://pckrl.com/\">Pickerel</a>: A tiny ramen bar. Interesting appetizers, drinks, and\ndesserts. It seems like the people working there enjoy working there. While\nyou’re in the neighbourhood: explore Luongo Square. If you’re waiting for\na seat at the bar, go across the square to <a href=\"https://averyprovidence.com/\">The Avery</a> while you wait.</li>\n</ul>\n\n"},{"id":"https://benjaminwil.info/weblog/rubyconf-mini","url":"https://benjaminwil.info/weblog/rubyconf-mini","external_url":null,"title":"RubyConf Mini","summary":"I attended RubyConf Mini in Providence, Rhode Island. If I met you there: it was a pleasure to have met you.","image":null,"banner_image":null,"date_published":"2022-11-26 12:54:53 -0700","date_modified":"2022-11-26 12:54:53 -0700","tags":["#<Lifer::Tag:0x00007fffdb6d9c18>","#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>I attended <a href=\"https://rubyconfmini.com\">RubyConf Mini</a> in Providence, Rhode Island. If I\nmet you there: it was a pleasure to have met you. This conference was a\nplanned-last-minute conference, relative to its partner conference,  RubyConf,\nin Austin. Their plan was to create much smaller, two-track conference for\nanyone unwilling or unable to go to Austin.</p>\n\n<p>If the conference happens again next year, and you’re at all interested in\nthe Ruby programming language, I would recommend attending.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/777","url":"https://benjaminwil.info/weblog/777","external_url":null,"title":"777","summary":"Recently I released an EP 777. You can stream it or purchase it on Bandcamp.","image":null,"banner_image":null,"date_published":"2022-06-01 11:37:53 -0700","date_modified":"2022-06-01 11:37:53 -0700","tags":["#<Lifer::Tag:0x00007fffdb7176f8>","#<Lifer::Tag:0x00007fffdb717478>"],"language":"en","content_html":"<p>Recently I released an EP <em>777</em>. You can stream it or purchase it <a href=\"https://bwbw.bandcamp.com/album/777\">on\nBandcamp</a>.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/2021-film","url":"https://benjaminwil.info/weblog/2021-film","external_url":null,"title":"The best films I saw: 2021 edition","summary":"As usual: here are thirty films, that I liked or thought were good, that I watched for the first time this year.","image":null,"banner_image":null,"date_published":"2021-12-31 12:00:00 -0700","date_modified":"2021-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>As usual: here are thirty films, that I liked or thought were good, that I\nwatched for the first time this year. In no particular order.</p>\n\n<ul>\n  <li>Éric Rohmer: <em>Six in Paris</em>,                            1965</li>\n  <li>Angela Schanelec: <em>I Was at Home, But…</em>,                2019</li>\n  <li>Geneviève Dulude-De Celles: <em>A Colony</em>,                 2018</li>\n  <li>Pedro Costa: <em>Vitalina Varela</em>,                         2019</li>\n  <li>Jackie Chan: <em>Police Story</em>,                            1985</li>\n  <li>Sean Baker: <em>Starlet</em>,                                  2012</li>\n  <li>Robert Altman: <em>California Split</em>,                      1974</li>\n  <li>Éric Rohmer: <em>Rendezvous in Paris</em>,                     1995</li>\n  <li>Spike Lee: <em>Bamboozled</em>,                                2000</li>\n  <li>Thomas Vinterberg: <em>Another Round</em>,                     2020</li>\n  <li>Éric Rohmer: <em>Sign of the Lion</em>,                        1962</li>\n  <li>Juzo Itami: <em>Tampopo</em>,                                  1985</li>\n  <li>Stanley Kubrick: <em>Eyes Wide Shut</em>,                      1999</li>\n  <li>Pietro Marcello: <em>Martin Eden</em>,                         2019</li>\n  <li>Nicolas Winding Refn: <em>Fear X</em>,                         2003</li>\n  <li>Solange Knowles: <em>When I Get Home</em>,                     2019</li>\n  <li>Kevin Jerome Everson: <em>Park Lanes</em>,                     2015</li>\n  <li>The Wachowskis: <em>Bound</em>,                                1996</li>\n  <li>Wes Craven: <em>Scream</em>,                                   1996</li>\n  <li>Spike Lee: <em>Da 5 Bloods</em>,                               2020</li>\n  <li>Apichatpong Weerasethakul: <a href=\"https://www.youtube.com/watch?v=8Hk4zepxyoE\"><em>Blue</em></a>,              2017</li>\n  <li>Tony Kaye: <em>American History X</em>,                        1998</li>\n  <li>Tsai Ming-liang: <a href=\"https://www.filmcomment.com/blog/film-week-afternoon-tsai-ming-liang/\"><em>Afternoon</em></a>,                   2015</li>\n  <li>Robin Hardy: <em>The Wicker Man</em>,                          1973</li>\n  <li>Leos Carax: <em>Annette</em>,                                  2021</li>\n  <li>James Wan: <em>Malignant</em>,                                 2021</li>\n  <li>Jean-Luc Godard: <em>First Name: Carmen</em>,                  1983</li>\n  <li>Corneliu Porumboiu: <em>Infinite Football</em>,                2018</li>\n  <li>John Maringouin: <em>Ghostbox Cowboy</em>,                     2018</li>\n  <li>Dasha Nekrasova: <em>The Scary of Sixty-First</em>,            2021</li>\n</ul>\n\n"},{"id":"https://benjaminwil.info/weblog/now-a-gollum-organization-member","url":"https://benjaminwil.info/weblog/now-a-gollum-organization-member","external_url":null,"title":"Now a Gollum organization member","summary":"Earlier this year, I was invited to join the Gollum organization after making some contributions to the main Gollum repos...","image":null,"banner_image":null,"date_published":"2021-11-02 19:04:00 -0700","date_modified":"2021-11-02 19:04:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>Earlier this year, I was invited to join the <a href=\"https://github.com/gollum\">Gollum organization</a> after\nmaking some contributions to the <a href=\"https://github.com/gollum/gollum\">main Gollum repository</a>. I’ve been\nparticipating by triaging incoming issues and bug reports, reviewing pull\nrequests, and contributing changes to improve the Gollum user experience for\nmobile users.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/no-longer-there","url":"https://benjaminwil.info/weblog/no-longer-there","external_url":null,"title":"No longer there","summary":"I released an EP called No longer there. You can stream it or purchase it on Bandcamp.","image":null,"banner_image":null,"date_published":"2021-07-07 09:00:00 -0700","date_modified":"2021-07-07 09:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb7176f8>","#<Lifer::Tag:0x00007fffdb717478>"],"language":"en","content_html":"<p>I released an EP called <em>No longer there</em>. You can stream it or purchase it <a href=\"https://bwbw.bandcamp.com/album/no-longer-there\">on\nBandcamp</a>.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/treatise-on-luck","url":"https://benjaminwil.info/weblog/treatise-on-luck","external_url":null,"title":"Treatise on Luck","summary":"Mark Francis Johnson’s Treatise on Luck is a book of poems that investigates luck: where it comes from, where it goes, an...","image":null,"banner_image":null,"date_published":"2021-01-31 12:00:00 -0700","date_modified":"2021-01-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb7b15a0>","#<Lifer::Tag:0x00007fffdb7b1118>"],"language":"en","content_html":"<p>Mark Francis Johnson’s <a href=\"https://www.gauss-pdf.com/post/162628927505/gpdf238gpdfe027-mark-francis-johnson-treatise\"><em>Treatise on Luck</em></a> is a book of poems that\ninvestigates luck: where it comes from, where it goes, and where it isn’t. It’s\na book from <a href=\"https://gauss-pdf.com\">Gauss PDF</a>, a digital publisher I am interested in.</p>\n\n<p>From the book:</p>\n\n<blockquote>\n  <p>The grooming staple I’m never without is<br />\nXD’s Eau Sauvage. It was the first fragrance<br />\nI drank when I was young. In a way, it was<br />\nmy first love. I am not sure if I’d still drink it<br />\nfor the love I felt for it back then or the<br />\nfragrance itself, or for luck. It’s nostalgic.</p>\n</blockquote>\n\n"},{"id":"https://benjaminwil.info/weblog/2020-film","url":"https://benjaminwil.info/weblog/2020-film","external_url":null,"title":"The best films I saw: 2020 edition","summary":"A marked improvement in my film consumption since 2019. The following list is thirty films long.","image":null,"banner_image":null,"date_published":"2020-12-31 12:00:00 -0700","date_modified":"2020-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>A marked improvement in my film consumption since 2019. The following list is\nthirty films long. All films I saw for the first time in 2020.</p>\n\n<ul>\n  <li>Alejandro Landes:          <em>Monos</em>,                   2019</li>\n  <li>Marcell Iványi:            <em>Wind</em>,                    1996</li>\n  <li>Éric Rohmer:               <em>My Night at Maud’s</em>,      1969</li>\n  <li>Sofia Bohdanowicz:         <a href=\"https://cinema-scope.com/cinema-scope-online/tiff-2020-point-and-line-to-plane-sofia-bohdanowicz-canada/\"><em>Point and Line to Plane</em></a>, 2020</li>\n  <li>Federico Fellini:          <em>I Vitelloni</em>,             1953</li>\n  <li>Jean-Luc Godard:           <em>Tout Va Bien</em>,            1972</li>\n  <li>Louis Malle:               <em>My Dinner with Andre</em>,    1981</li>\n  <li>Jim Jarmusch:              <em>Night on Earth</em>,          1991</li>\n  <li>Jodie Mack:                <a href=\"https://mubi.com/notebook/posts/jodie-mack-introduces-her-film-the-grand-bizarre\"><em>The Grand Bizarre</em></a>, 2018</li>\n  <li>Pablo Larraín:             <em>Ema</em>,                     2019</li>\n  <li>Olivier Assayas:           <em>Carlos</em>,                  2010</li>\n  <li>Crystal Moselle:           <em>Skate Kitchen</em>,           2018</li>\n  <li>Kazik Radwanski:           <em>Anne at 13,000 ft</em>,       2019</li>\n  <li>Raoul Peck:                <em>I Am Not Your Negro</em>,     2016</li>\n  <li>Nicolas Winding Refn:      <em>Pusher</em>,                  1996</li>\n  <li>Terrence Malick:           <em>Days of Heaven</em>,          1978</li>\n  <li>Spike Lee:                 <em>Malcolm X</em>,               1992</li>\n  <li>François Truffaut:         <em>Antoine and Colette</em>,     1962</li>\n  <li>Dash Shaw: <em><a href=\"https://brieftake.com/interview-my-entire-high-school-s-dash-shaw/\">My Entire High School Sinking Into the Sea</a></em>, 2016</li>\n  <li>Paul Harrill:              <em>Light from Light</em>,        2019</li>\n  <li>Peter Bogdanovich:         <em>Targets</em>,                 1968</li>\n  <li>Ladj Ly:                   <em>Les Misérables</em>,          2019</li>\n  <li>Spencer Williams:         <a href=\"https://en.wikipedia.org/wiki/The_Blood_of_Jesus\"><em>The Blood of Jesus</em></a>, 1941</li>\n  <li>François Truffaut:         <em>Jules and Jim</em>,           1962</li>\n  <li>Guy Maddin:                <em>Brand Upon the Brain!</em>,   2006</li>\n  <li>Philippe Lesage:           <em>Genesis</em>,                 2018</li>\n  <li>Tsai Ming-liang:           <em>Walker</em>,                  2012</li>\n  <li>Scott Cummings:            <a href=\"https://buffalojuggalosfilm.tumblr.com\"><em>Buffalo Juggalos</em></a>,  2014</li>\n  <li>Éric Rohmer:            <em>The Bakery Girl on Monceau</em>, 1963</li>\n  <li>Lev Kalman, Whitney Horn:  <em>Two Plains &amp; a Fancy</em>, 2018</li>\n</ul>\n\n"},{"id":"https://benjaminwil.info/weblog/assimilated","url":"https://benjaminwil.info/weblog/assimilated","external_url":null,"title":"Assimilated","summary":"I just released a new LaunchBar 6 theme called Assimilated.","image":null,"banner_image":null,"date_published":"2020-12-25 12:00:00 -0700","date_modified":"2020-12-25 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb5d1b40>","#<Lifer::Tag:0x00007fffdb5d18c0>"],"language":"en","content_html":"<p>I just released a new <a href=\"https://www.obdev.at/products/launchbar/index.html\">LaunchBar 6</a> theme called Assimilated.</p>\n\n<p>I am kind of shocked that I still use LaunchBar, but as long as I use macOS for\nwork I guess I’ll be using LaunchBar, too. Like <a href=\"https://github.com/benjaminwil/bijou\">Bijou</a>, my five-year-old\ntheme, I wanted a LaunchBar theme that would blend in with the macOS window\nchrome. With the release of Big Sur, I needed to create a completely new theme.</p>\n\n<p><a href=\"https://github.com/benjaminwil/assimilated\">See the GitHub repo</a> for more information and installation instructions.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/letter-for-you","url":"https://benjaminwil.info/weblog/letter-for-you","external_url":null,"title":"Letter for you","summary":"I released some music last week. It’s a short album called Letter for you. You can stream it or purchase it on Bandcamp.","image":null,"banner_image":null,"date_published":"2020-12-21 09:00:00 -0700","date_modified":"2020-12-21 09:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb7176f8>","#<Lifer::Tag:0x00007fffdb717478>"],"language":"en","content_html":"<p>I released some music last week. It’s a short album called <em>Letter for\nyou</em>. You can stream it or purchase it <a href=\"https://bwbw.bandcamp.com/album/letter-for-you\">on Bandcamp</a>. Bandcamp is also a\ngreat place to read the lyrics for each song.</p>\n\n<p>I hope you enjoy the release.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/film-title-poem-2016","url":"https://benjaminwil.info/weblog/film-title-poem-2016","external_url":null,"title":"Film Title Poem (2016)","summary":"Please also read Jennifer West’s introduction to the film.","image":null,"banner_image":null,"date_published":"2020-07-30 11:00:00 -0700","date_modified":"2020-07-30 11:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb70d630>"],"language":"en","content_html":"<p><em>Please also read <a href=\"https://mubi.com/notebook/posts/jennifer-west-introduces-her-film-film-title-poem\" target=\"_blank\">Jennifer West’s introduction to the film</a>.</em></p>\n\n<p>Of the many shorts I’ve seen that appropriate and then collage movie stills or\nsequences, I interpret Film Title Poem as one of the more appreciative ones. In\nit, Jennifer West shines a flashlight on many of the films in the western\ncanon, the ones that either have weird staying power (<em>Men in Black</em>)\nor are held up as cult classics to the cinephiles (<em>L’Avventura</em>)\nor are the more obscure works of particular filmmakers who are considered\ncanonical (Gus Van Sant’s <em>Paranoid Park</em>). There are even shout-outs\nto some very revered experimental titles (go <em>T,O,U,C,H,I,N,G</em>,\n<em>Moth Light</em>). I should also mention the expertly stolen soundtrack,\nfeaturing scores from <em>Solaris</em> among other movies I’m blanking on,\neven though the music is still as clear as can be in my memory.</p>\n\n<p>When I say, “shines a flashlight,” I mean exactly that. As someone with\nwarm feelings for the majority of these movies, I was happy to see them\nbeing rediscovered on this wall of film titles somewhere. The titles are\npresented in half-alphabetical order, half-some sort of order. In some\nmoments I looked for meaning in the order: hidden sequences in the blinking,\nthe repetition of some titles. I didn’t get very far reading the film like\nthis, but didn’t mind either way. I was more focused on the Brakhagian\nscratches in the celluloid, highlighting movie-crushes and crossing out the\n(?) trash. Whether you can enjoy following along on this late-night tour\nor not, I think there’s value in flipping through these film titles with\nvery little other context, re-evaluating them on the spot, re-evaluating my\nmemories of them, and pitting them against the other film titles on the wall.</p>\n"},{"id":"https://benjaminwil.info/weblog/self-hosted-git-remote","url":"https://benjaminwil.info/weblog/self-hosted-git-remote","external_url":null,"title":"Self-hosting a tiny git remote","summary":"There are plenty of full-featured git forges out there.","image":null,"banner_image":null,"date_published":"2020-03-22 12:00:00 -0700","date_modified":"2020-03-22 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb1a3668>","#<Lifer::Tag:0x00007fffdb1a3528>"],"language":"en","content_html":"<p>There are plenty of full-featured git forges out there. If you’re a software\ndeveloper, you’ve probably used GitHub, Bitbucket, and GitLab at some point –\nand you’re maybe familiar with <a href=\"https://gitea.io\">Gitea</a>,\n<a href=\"https://gogs.io\">Gogs</a>, or <a href=\"https://sr.ht\">SourceHut</a>.</p>\n\n<p>All of this software is great, and each git forge has valuable features that save\nusers time and effort when working on projects.</p>\n\n<p>Sometimes, though, all I need is a simple <a href=\"https://git-scm.com/docs/git-remote\">git remote</a> to sync\na simple project. I don’t need issue trackers, wikis, continuous integration,\nor a way to manage patches coming from multiple contributors.</p>\n\n<p>For these use cases, I have set up a tiny git remote that only I can access.</p>\n\n<h2 id=\"create-a-synced-directory\">Create a synced directory</h2>\n\n<p>The first problem that needs solving: where should the remote live? I have\nchosen to use a simple synced directory.</p>\n\n<p>There is nothing special about this directory. It is just another directory I\nintend to sync using some Dropbox-like file syncing software. (Don’t worry: I do\nnot ever sync working directories. I’ll discuss this later.)</p>\n\n<p>We have many ways to sync directories in 2020: whether you use a hosted service\nlike Google Drive or use a self-hosted solution like\n<a href=\"https://owncloud.org/\">ownCloud</a>. I personally use\n<a href=\"https://syncthing.net/\">Syncthing</a>, which runs 24/7 on a media server in my\nliving room – and then syncs to all my other devices whenever they’re connected\nto a network.</p>\n\n<p>The directory I sync is simply called <code>Git</code>. It lives in my user’s <code>$HOME</code> directory.</p>\n\n<p>If you’re asking yourself, “why not just use SSH?” right now, I suggest skipping\nto the <a href=\"#why-not-just-use-ssh\">Why not just use SSH?</a> section of this article.</p>\n\n<h2 id=\"add-new-repositories\">Add new repositories</h2>\n\n<p>The next problem is: how to get <code>project-directory</code> from <em>Computer A</em> to\n<em>Computer B</em>. The short answer would be, “use the synced directory” – but I want\nto do this the right way.<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup></p>\n\n<p>In my <code>Git</code> directory, I can start to <a href=\"https://git-scm.com/docs/git-init\">initialize git\nrepositories</a> with the <code>--bare</code> flag:</p>\n\n<p><code>\ngit init --bare ~/Git/my-project.git\n</code></p>\n\n<p>The <code>--bare</code> flag means that the git repository being initialized (or cloned,\nactually) is <em>not</em> going to be a working directory.</p>\n\n<p>If I try to change directory to my new repo, git even warns me about this:</p>\n\n<p><code>\ncd ~/Git/my-project.git\nfatal: this operation must be run in a work tree\n</code></p>\n\n<p>You can read more about using bare git repositories this way in the <em>Pro Git</em>\nbook. Specifically, see <a href=\"https://git-scm.com/book/en/v2/Git-on-the-Server-Getting-Git-on-a-Server\">4.2 Git on the Server – Getting Git on a\nServer</a>.</p>\n\n<h2 id=\"push-to-repositories\">Push to repositories</h2>\n\n<p>I’m about ready to push work. So far, I’ve:</p>\n\n<ul>\n  <li>Built a home for git repositories I want to sync: <code>~/Git</code>.</li>\n  <li>Made my first bare git repository at <code>~/Git/my-project.git</code>.<sup id=\"fnref:2\"><a href=\"#fn:2\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">2</a></sup></li>\n</ul>\n\n<p>Now, I can take any working directory and add my bare repository as a remote:</p>\n\n<p><code>\ngit remote add syncthing ~/Git/my-project.git\n</code></p>\n\n<p>And when I’m ready to push my work from my branch (in this case <code>my-branch</code>):</p>\n\n<p><code>\ngit push syncthing my-branch\n</code></p>\n\n<h2 id=\"clone-repositories\">Clone repositories</h2>\n\n<p>When I’m ready to clone the project from another workstation, I just need\nto make sure my synced directory is available and fully synced. The messiest\npart of this is that (with Syncthing, at least) the synced directory <em>may</em> use a\ndifferent path on my different workstations.</p>\n\n<p>When I clone, it’s nice to manually set the <code>--origin</code> so I’m mindful that I’m\npushing to and pulling from my tiny git remote:</p>\n\n<p><code>\ngit clone --origin syncthing ~/Git/my-project.git\n</code></p>\n\n<p>And if I forget (like I often do), I can always change the name of the remote\nlater using <code>git remote rename</code>:</p>\n\n<p><code>\ngit clone ~/Git/my-project.git my-project\ncd my-project\ngit remote rename origin syncthing\n</code></p>\n\n<h2 id=\"caveats\">Caveats</h2>\n\n<p>My tiny git remote works great for small projects I don’t intend to share with\nanyone. But I think it’s important to highlight the caveats:</p>\n\n<ul>\n  <li>If my syncing software fails (on the server <em>or</em> a client), I risk losing work.</li>\n  <li>If this is my only git remote, I risk losing work. I must use multiple git\nremotes.</li>\n</ul>\n\n<p>If my syncing software does fail, but I’ve already cloned my project on\nmultiple workstations, I <em>may</em> be able to recover. That said, I do need to\nbe conscious of the state of my syncing software if I want to successfully\nuse my tiny remote.</p>\n\n<h2 id=\"why-not-just-use-ssh\">Why not just use SSH?</h2>\n\n<p>Some readers have rightly pointed out that this setup is more complex and has\nmore caveats than just pulling from your other workstations via SSH:</p>\n\n<p><code>\ngit remote add workstation_2 benjaminwil@111.111.11.11:/home/benjaminwil/my-project\n</code></p>\n\n<p>If I’m lucky: <code>111.111.11.11</code> is a static IP address that I already know. And if\nI’m really lucky: it’s just a domain name, like <code>benjaminwil.info</code>. Luck has\nnothing to do with it, but you know what I mean.</p>\n\n<p>The reasons that I prefer using a synced directory, as described in this\narticle, are:</p>\n\n<ul>\n  <li>There is built-in redundancy. Syncthing makes local copies of my latest\nchanges whenever a workstation running Syncthing is on a network.</li>\n  <li>I am lazy. I am too often wiping my secondary devices and not setting up SSH\nkeys to my primary devices.</li>\n  <li>I don’t personally have a static IP address at home. While there are ways to\ntake care of that problem, I haven’t ventured down that path.</li>\n</ul>\n\n<p>All that said, I also have a remote set up that I only access via SSH. It’s my\n“always off-site” backup, and it is very valuable to me.</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>I could technically work out of a project directory that’s actively being\n  synced. But there are lots of files I don’t want to or need to sync.</p>\n\n      <p>Syncing would occur more slowly if I had to sync 200MB of NodeJS modules\n  between workstations. And if I accidentally leave a process running on\n  <em>Workstation A</em> and then start work from <em>Workstation B</em>, I could cause\n  some weird problems for myself. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:2\">\n      <p>I don’t have to add <code>.git</code> to the end of a bare git repo, but it’s a\n  nice convention. <a href=\"#fnref:2\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/2019-film","url":"https://benjaminwil.info/weblog/2019-film","external_url":null,"title":"The best films I saw: 2019 edition","summary":"I watched a lot of mediocre and objectively-pretty-bad movies this year.","image":null,"banner_image":null,"date_published":"2019-12-31 12:00:00 -0700","date_modified":"2019-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>I watched a lot of mediocre and objectively-pretty-bad movies this year. So much\nso that I don’t think I can get to a list that’s thirty items’ long (as I did in\n<a href=\"/weblog/2018-film\">2018</a> and <a href=\"/weblog/2017-film\">2017</a>). That said, I watched some pretty wonderful\nthings:</p>\n\n<ul>\n  <li>James Benning: <em><a href=\"http://rarefilm.net/american-dreams-lost-and-found-1984-james-benning-documentary/\">American Dreams (Lost and Found)</a></em>, 1984</li>\n  <li>Sofia Bohdanowicz, Deragh Campbell: <em><a href=\"https://cinema-scope.com/features/audrey-ii-sofia-bohdanowicz-and-deragh-campbells-ms-slavic-7/\">MS Slavic 7</a></em>, 2019</li>\n  <li>Virgil Vernier: <em><a href=\"https://www.filmcomment.com/article/mercuriales-virgil-vernier/\">Mercuriales</a></em>, 2014</li>\n  <li>Bong Joon-Ho: <em>Memories of Murder</em>, 2003</li>\n  <li>Paweł Pawlikowski: <em>Cold War</em>, 2018</li>\n  <li>Kazuhiro Sôda: <em><a href=\"https://www.nytimes.com/2008/04/07/movies/07camp.html?_r=0\">Campaign</a></em>, 2007</li>\n  <li>Apichatpong Weerasethakul: <a href=\"https://en.wikipedia.org/wiki/Uncle_Boonmee_Who_Can_Recall_His_Past_Lives\">Uncle Boonmee Who Can Recall His Past\nLives</a>, 2010</li>\n  <li>Ricky D’Ambrose: <em><a href=\"https://www.villagevoice.com/2018/08/14/ricky-dambroses-minimalist-notes-on-an-appearance-is-obsessed-with-absence/\">Notes on an Appearance</a></em>, 2018</li>\n  <li>Agnès Varda: <em>Le Bonheur</em>, 1965</li>\n  <li>Lucien Castaing-Taylor, Véréna Paravel: <em><a href=\"https://en.wikipedia.org/wiki/Leviathan_(2012_film)\">Leviathan</a></em>, 2012</li>\n  <li>Nathan Silver: <em><a href=\"https://www.rogerebert.com/reviews/stinking-heaven-2015\">Stinking Heaven</a></em>, 2015</li>\n  <li>Sofia Bohdanowicz: <em>Veslemoy’s Song</em>, 2018</li>\n  <li>Manbiki Kazoku: <em>Shoplifters</em>, 2018</li>\n  <li>Toshio Matsumoto: <em><a href=\"https://en.wikipedia.org/wiki/Funeral_Parade_of_Roses\">Funeral Parade of Roses</a></em>, 1969</li>\n  <li>Robert Hamilton: <em>The Five Finger Splash</em>, 2019 <a href=\"https://vimeo.com/315744145\">🎥</a></li>\n  <li>Rodrigo Sorogoyen: <em>The Realm</em>, 2018</li>\n  <li>Ethan Coen, Joel Coen: <em>The Ballad of Buster Scruggs</em>, 2019</li>\n  <li>Noah Baumbach: <em>Marriage Story</em>, 2019</li>\n  <li>Bong Joon-Ho: <em>Parasite</em>, 2019</li>\n  <li>Ryan Ermacora, Jessica Johnson: <em><a href=\"https://jessicajohnson.ca/labour%2Fleisure\">Labour/Leisure</a></em>, 2019</li>\n</ul>\n\n<p>Due to this feeling incomplete to me, here are some non-movie things that might\nhave made this list in the parallel universe:</p>\n\n<ul>\n  <li><em>Mindhunter</em> (season two)</li>\n  <li><em>Watchmen</em></li>\n  <li>Jane Campion, Gerard Lee, and Garth Davis’ <em><a href=\"https://en.wikipedia.org/wiki/Top_of_the_Lake\">Top of the Lake</a></em> (season\none)</li>\n  <li>Nicholas Winding Refn’s <em><a href=\"https://en.wikipedia.org/wiki/Too_Old_to_Die_Young\">Too Old to Die Young</a></em></li>\n</ul>\n\n"},{"id":"https://benjaminwil.info/weblog/2018-film","url":"https://benjaminwil.info/weblog/2018-film","external_url":null,"title":"The best films I saw: 2018 edition","summary":"For film-watching, 2018 wasn’t as good to me as 2017. But I did see a handful of movies worth remembering.","image":null,"banner_image":null,"date_published":"2018-12-31 12:00:00 -0700","date_modified":"2018-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>For film-watching, 2018 wasn’t as good to me as 2017. But I did see a handful of\nmovies worth remembering. The following list is thirty films long – all films that\nI saw for the first time this year.</p>\n\n<ul>\n  <li>Eric Baudelaire: <em><a href=\"http://cinema-scope.com/spotlight/letters-max-eric-baudelaire-france/\">Letters to Max</a></em>, 2014</li>\n  <li>Spike Lee: <em><a href=\"https://en.wikipedia.org/wiki/Crooklyn\">Crooklyn</a></em>, 1994</li>\n  <li>John Cassavetes: <em><a href=\"https://film.avclub.com/john-cassavetes-final-major-work-love-streams-is-an-1798181120\">Love Streams</a></em>, 1984</li>\n  <li>Alexander Sokurov: <em><a href=\"https://mubi.com/notebook/posts/god-and-man-aleksandr-sokurovs-the-sun\">The Sun</a></em>, 2015</li>\n  <li>Pedro Costa: <em><a href=\"https://en.wikipedia.org/wiki/Colossal_Youth_(film)\">Collosal Youth</a></em>, 2006</li>\n  <li>Bingham Bryant &amp; Kyle Molzan: <em><a href=\"https://variety.com/2016/film/reviews/for-the-plasma-review-1201808672/\">For the Plasma</a></em>, 2016</li>\n  <li>Jacques Audiard: <em><a href=\"https://www.tiff.net/tiff/the-sisters-brothers/\">The Sisters Brothers</a></em>, 2018</li>\n  <li>Jonas Mekas: <em><a href=\"https://www.nga.gov/features/experimental-cinema-in-eastern-europe/historys-shadow/reminiscences-of-a-journey-to-lithuania.html\">Reminiscences of a Trip to Lithuania</a></em>, 1972</li>\n  <li>Sean Baker: <em>The Florida Project</em>, 2017</li>\n  <li>Luca Guadagnino: <em>Call Me by Your Name</em>, 2017</li>\n  <li>Steven Soderbergh: <em>Unsane</em>, 2018</li>\n  <li>Agnès Varda: <em>Kung-fu master!</em>, 1988</li>\n  <li>Steve James: <em><a href=\"https://en.wikipedia.org/wiki/Hoop_Dreams\">Hoop Dreams</a></em>, 1994</li>\n  <li>Tom DeCillo: <em><a href=\"http://www.tomdicillo.com/portfolio/down-in-shadowland/\">Down in Shadowland</a></em>, 2014</li>\n  <li>Boots Riley: <em>Sorry to Bother You</em>, 2018</li>\n  <li>Renata Gąsiorowska: <em>Pussy</em>, 2016 <a href=\"https://vimeo.com/308707509\">🎥</a></li>\n  <li>Ruben Östlund: <em>The Square</em>, 2017</li>\n  <li>Lynne Ramsay: <em>You Were Never Really Here</em>, 2018</li>\n  <li>Jacques Rivette: <em>Wuthering Heights</em>, 1985</li>\n  <li>Angela Schanelec: <em><a href=\"http://worldscinema.org/2015/01/angela-schanelec-mein-langsames-leben-aka-passing-summer-2001/\">Passing Summer</a></em>, 2001</li>\n  <li>Kevin Jerome Everson: <em>Three Quarters</em>, 2015</li>\n  <li>Benoît Forgeard: <em>Respect</em>, 2011</li>\n  <li>Paul Thomas Anderson: <em>Phantom Thread</em>, 2017</li>\n  <li>Denis Côté: <em>Curling</em>, 2010</li>\n  <li>Gastón Solnicki: <em><a href=\"http://cinema-scope.com/spotlight/kekszakallu-gaston-solnicki-argentina/\">Kékszakállú</a></em>, 2016</li>\n  <li>Greta Gerwig: <em>Lady Bird</em>, 2017</li>\n  <li>Alex Ross Perry: <em>Golden Exits</em>, 2017</li>\n  <li>Éric Rohmer: <em><a href=\"http://sensesofcinema.com/2017/1967/la-collectionneuse/\">La Collectionneuse</a></em>, 1967</li>\n  <li>Yorgos Lanthimos: <em>The Favourite</em>, 2018</li>\n  <li>Wes Anderson: <em>Isle of Dogs</em>, 2018</li>\n  <li>Hugh Gibson: <em><a href=\"https://www.theglobeandmail.com/arts/film/film-reviews/no-happy-endings-in-hugh-gibsons-the-stairs/article32228963/\">The Stairs</a></em>, 2016</li>\n</ul>\n\n"},{"id":"https://benjaminwil.info/weblog/bijou","url":"https://benjaminwil.info/weblog/bijou","external_url":null,"title":"Bijou","summary":"I updated my LaunchBar 6 theme Bijou (previously called El Capitan Small).","image":null,"banner_image":null,"date_published":"2018-09-30 12:00:00 -0700","date_modified":"2018-09-30 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb5d1b40>","#<Lifer::Tag:0x00007fffdb5d18c0>"],"language":"en","content_html":"<p>I updated my <a href=\"https://www.obdev.at/products/launchbar/index.html\">LaunchBar 6</a> theme Bijou (previously called <a href=\"/weblog/el-capitan-small\">El Capitan\nSmall</a>). Now, the theme has a dark variant to match macOS Mojave’s new dark\nmode. It also got its new name and features some small tweaks that make\nit more visually consistent.</p>\n\n<p><a href=\"https://github.com/benjaminwil/bijou\">See the GitHub repo</a> for more information and installation instructions.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/public-access-unix-servers-as-a-service","url":"https://benjaminwil.info/weblog/public-access-unix-servers-as-a-service","external_url":null,"title":"Public access Unix servers as a service","summary":"A public access Unix (or Unix-like) server is just a computer.","image":null,"banner_image":null,"date_published":"2018-07-21 12:07:00 -0700","date_modified":"2018-07-21 12:07:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb885fa8>","#<Lifer::Tag:0x00007fffdb885210>"],"language":"en","content_html":"<p>A public access Unix (or Unix-like) server is just a computer. What makes it\nspecial is that anybody can sign up for a user account and use the computer.</p>\n\n<p>I would consider these servers proto-social networks: no matter what activities\nyou participate in on the server (message boards, chat, blogging, personal\nprojects, shared application development), you’re contributing to the server\ncommunity.</p>\n\n<p>The most famous public access server is <a href=\"https://en.wikipedia.org/wiki/SDF_Public_Access_Unix_System\">SDF</a>. It has existed\nsince 1987 and still has a growing user base. From 1987-era <a href=\"https://en.wikipedia.org/wiki/Gopher_%28protocol%29\">Gopher sites</a>,\nto traditional web forums, to multi-user Minecraft, SDF hosts a wide-range of\nservices for—and by—its users.</p>\n\n<p>Currently, on the homepage of this site, I call myself a “public access Unix\nserver enthusiast.” I began my journey with public access servers as a member of\n<a href=\"http://tilde.club\">tilde.club</a><sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup> (unfortunately inactive these days), and I now contribute to\n<a href=\"http://tilde.town\">tilde.town</a>.</p>\n\n<p>I understand that intentionally accessing a server via the command line, and\nknowing how to do that, is not something that every person can do or would want\nto do. However, I hope you consider the ways that these servers can offer\nspaces for social experimentation that can pave the way for future, more refined\nnetworks and online spaces:</p>\n\n<ul>\n  <li>These servers are fundamentally non-commercial. They operate on personal\ntrust.</li>\n  <li>These servers promote technical literacy and offer the potential of education\nand mentorship.</li>\n  <li>Server information infrastructure is flexible and “designed” by active users.\nUsers are the primary stakeholders, investors, and feature-implementers in\ntheir community.</li>\n  <li>Users intentionally create and have control over their own data.</li>\n  <li>These servers provide the opportunity for users to host their own\nunconventional websites, blogs, and web apps, for free (or some reasonable\nmembership fee).</li>\n</ul>\n\n<p>There is also talk of federating some tilde-named servers. You can see the\nbeginnings of this at <a href=\"https://tilde.chat\">tilde.chat</a>. Currently, tilde.chat connects four\ntilde-named servers via IRC.</p>\n\n<p>For me, these are just a few reasons that make public access servers compelling.\nAnd seeing <a href=\"https://medium.com/@NotBrunoAgain/mastodon-the-obligatory-explainer-3c8a63467828\">the recent success of Mastodon</a>, and how it seemingly shares\nsome of the same values, specifically around ownership, identity, and privacy.\nIt validates my belief that these servers are forerunners in an emerging web\nculture, not just hobby spots for outsider tech nerds.</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>See Paul Ford’s article <a href=\"https://medium.com/message/tilde-club-i-had-a-couple-drinks-and-woke-up-with-1-000-nerds-a8904f0a2ebf\">Tilde.Club: I had a couple drinks and woke up with 1,000 nerds</a> for more information about tilde.club. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/site-update","url":"https://benjaminwil.info/weblog/site-update","external_url":null,"title":"Site update","summary":"I just updated benjaminwil.info to use a new layout.","image":null,"banner_image":null,"date_published":"2018-07-08 12:00:00 -0700","date_modified":"2018-07-08 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb713f80>","#<Lifer::Tag:0x00007fffdb7130f8>"],"language":"en","content_html":"<p>I just updated <a href=\"https://benjaminwil.info\">benjaminwil.info</a> to use a new layout. It’s still built with\n<a href=\"https://jekyllrb.com\">Jekyll</a>, and it’s still hosted on <a href=\"https://m.do.co/c/4b641d12a82b\">a DigitalOcean droplet</a>—but I cut\nout fifty percent of the CSS and made site maintenance <em>much</em> easier for myself.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/2017-film","url":"https://benjaminwil.info/weblog/2017-film","external_url":null,"title":"The best films I saw: 2017 edition","summary":"I am sharing with you thirty films that I saw this year, that I liked.","image":null,"banner_image":null,"date_published":"2017-12-31 12:00:00 -0700","date_modified":"2017-12-31 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb704300>"],"language":"en","content_html":"<p>I am sharing with you thirty films that I saw this year, that I liked. They\ndefinitely did not all come out this year, or even recently. They are listed\nbelow in a definite order.</p>\n\n<ul>\n  <li>Maren Ade: <em><a href=\"https://www.bfi.org.uk/news-opinion/sight-sound-magazine/reviews-recommendations/toni-erdmann-maren-ade-shaggy-dad-comedy\">Toni Erdmann</a></em>, 2016</li>\n  <li>Nanni Moretti: <em>Sweet Dreams</em>, 1981</li>\n  <li>Huang Ya-Li: <em><a href=\"https://www.cinema.ucla.edu/events/2017/11/05/moulin\">Le Moulin</a></em>, 2015</li>\n  <li>Jordan Peele: <em>Get Out</em>, 2017</li>\n  <li>James N. Kienitz Wilkins: <em>Public Hearing</em>, 2012 <a href=\"https://vimeo.com/ondemand/publichearing\">🎥</a></li>\n  <li>Jay Rosenblatt: <em>Restricted</em>, 1999</li>\n  <li>Ai Weiwei: <em><a href=\"https://en.wikipedia.org/wiki/Human_Flow\">Human Flow</a></em>, 2017</li>\n  <li><a href=\"https://mubi.com/notebook/posts/ghosts-of-time-and-light-the-experimental-cinema-of-ito-takashi\">Takashi Ito</a>: <em>Double</em>, 2001</li>\n  <li>James N. Kienitz Wilkins: <em><a href=\"https://mubi.com/notebook/posts/e-uno-plura-close-up-on-james-n-kienitz-wilkins-the-republic\">The Republic</a></em>, 2017</li>\n  <li>Arthur Lipsett: <em>21-87</em>, 1963 <a href=\"https://vimeo.com/29432400\">🎥</a></li>\n  <li>Casimir Nozkowski: <em>IDAC</em>, 2016 <a href=\"https://www.youtube.com/watch?v=OvCum88STm8\">🎥</a></li>\n  <li>Michael Winterbottom: <em>The Trip</em>, 2010</li>\n  <li>Olivier Assayas: <em><a href=\"http://cinema-scope.com/cinema-scope-online/personal-shopper-olivier-assayas-france-masters/\">Personal Shopper</a></em>, 2016</li>\n  <li>Kevan Funk: <em><a href=\"https://www.cbc.ca/news/entertainment/kevan-funk-hello-destroyer-1.4019785\">Hello Destroyer</a></em>, 2016</li>\n  <li>Ousmane Sembene: <em>Black Girl</em>, 1966</li>\n  <li>Sofia Coppola: <em>The Beguiled</em>, 2017</li>\n  <li>Takashi Ito: <em>December Hide-and-Go-Seek</em>, 1993</li>\n  <li>Laura Poitras: <em>Risk</em>, 2016</li>\n  <li>Dana Berman Duff: <em>Catalogue Vol. 6</em>, 2016 <a href=\"https://vimeo.com/204550609\">🎥</a></li>\n  <li>Chris King: <em>Wipe Poem</em>, 2017 <a href=\"https://vimeo.com/62649373\">🎥</a></li>\n  <li>David Leitch: <em>Atomic Blonde</em>, 2017</li>\n  <li>Jeffrey Chong: <em>Kingsway</em>, 2017</li>\n  <li>Alabart, Cros, Verheyen, Rius: <em><a href=\"https://www.hollywoodreporter.com/review/agata-s-friends-les-amigues-909581\">Agata’s Friends</a></em>, 2015</li>\n  <li>Chris Marker: <em>La Jetée</em>, 1962 <a href=\"https://www.youtube.com/watch?v=6anMLFwHFqs\">🎥</a></li>\n  <li>Jodie Mack: <em>Wasteland No. 1: Ardent, Verdant</em>, 2017</li>\n  <li>Maurice Pialat: <em><a href=\"https://lwlies.com/articles/a-nos-amours-maurice-pialat-greatest-teen-movie/\">À Nos Amours</a></em>, 1983</li>\n  <li>Hayao Miyazaki: <em>Kiki’s Delivery Service</em>, 1989</li>\n  <li>Tom McCarthy: <em>Spotlight</em>, 2015</li>\n  <li>Tim Sutton: <em><a href=\"https://www.theguardian.com/film/2017/aug/18/dark-night-review-tim-sutton-aurora-massacre\">Dark Night</a></em>, 2016</li>\n  <li>Peter Weir: <em>Picnic at Hanging Rock</em>, 1975</li>\n</ul>\n\n"},{"id":"https://benjaminwil.info/weblog/the-republic-2017","url":"https://benjaminwil.info/weblog/the-republic-2017","external_url":null,"title":"The Republic (2017)","summary":"The Republic meets my threshold for something that is a movie, despite there being almost nothing to see.","image":null,"banner_image":null,"date_published":"2017-07-30 12:00:00 -0700","date_modified":"2017-07-30 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb6f0378>","#<Lifer::Tag:0x00007fffdb70d630>"],"language":"en","content_html":"<p><em>The Republic</em> meets my threshold for something that is a movie,\ndespite there being almost nothing to see. If you don’t already know: <em>The\nRepublic</em> doesn’t utilize a camera. It presents solid colours only… and\nquite slowly. You could call it a gimmick, but be aware that it is one entry\ninto a category of films that do the exact same thing—notably Derek Jarman’s\n<em>Blue</em>—and still manage to do a new thing. This entry holds interest\nby grounding the viewer in  uncomplicated radioplay storytelIing, relieving us\nof the genuinely uncomfortable, OLED-destroying, static abstraction on screen.</p>\n\n<p>Since you won’t be seeing much, pay attention to the warmth of the\noccasional flourishes that create sound-images in a mostly barren\n(apocalyptic?) sound-world. Most memorably, there is a doorbell effect that\nprovides additional relief from what’s on screen, and from the detached,\nminimal presentation of sound stage and many of the vocal performances. I\ndon’t have 7.1 surround at home and don’t believe this medium-fidelity\nproduction would have benefited from it anyway.</p>\n\n<p>The story describes a group of libertarian outsiders (and e-cigarette\nenthusiasts) delicately. Here, in 2010s North America, the libertarians that\nget clipped are either loud or dangerous, and so I urge you to take a breath\nand reframe before watching, so you can “get behind” an extended scenario\nfollowing the downfall of this sovereign of (very serious) libertarians who\nwant deeply for their society to function.</p>\n\n<p>Of all the performances, Nour Mobarak’s performance stands out.</p>\n"},{"id":"https://benjaminwil.info/weblog/sleep-when-exhausted-revisited","url":"https://benjaminwil.info/weblog/sleep-when-exhausted-revisited","external_url":null,"title":"Sleep when exhausted, revisited","summary":"Three years after first presenting Sleep when exhausted, I was invited back to the University of Victoria to give a short...","image":null,"banner_image":null,"date_published":"2017-02-02 00:00:00 +0000","date_modified":"2017-02-02 00:00:00 +0000","tags":["#<Lifer::Tag:0x00007fffdb6ff558>"],"language":"en","content_html":"<p>Three years after first presenting <a href=\"https://sleepwhen.benjaminwil.info\"><em>Sleep when\nexhausted</em></a>, I was invited back to the\nUniversity of Victoria to give a short talk about it in <a href=\"http://davidleach.ca\">David\nLeach</a>’s WRIT 324 class.<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup> It turns out that giving a\ntalk is the best possible excuse to revisit old work, especially when you’re a\nlittle embarrassed about it.</p>\n\n<p>This post is based on that talk. It also attempts to extrapolate on the jokey,\ncryptic stuff that appears in <a href=\"/weblog/sleep-when-exhausted\">the essay that accompanied the\nproject</a>.</p>\n\n<h2 id=\"what-is-this-thing\">What is this thing?</h2>\n\n<p><em>Sleep when exhausted</em> is a looping visual poem.<sup id=\"fnref:2\"><a href=\"#fn:2\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">2</a></sup> That means that it begs to\nbe read over and over again. If you choose to go through it more than once,\nyou’ll notice that the poem changes depending on the lines you pick out. But the\npremise of <em>Sleep when exhausted</em>, at its simplest, is that it’s a poem.</p>\n\n<p>For me, re-reading poetry is a necessary part of reading poetry. Every time I\nread a poem, I’ll linger on slightly different details, or the same singular\ndetail with some other cadence. This project formalizes that re-reading process.\nUnless you’re mapping out the lines that you’re picking, you probably won’t go\nthrough <em>Sleep when exhausted</em> the same way twice.</p>\n\n<p>Even now, as I’ve been going through it again, I get surprised by certain things\nthat I don’t even remember writing. Like the clock that reads <code>99:99</code> on the\npiano in the living room.</p>\n\n<h2 id=\"why-make-a-poem-out-of-a-website\">Why make a poem out of a website?</h2>\n\n<p>I received something that the University of Victoria calls a <a href=\"https://www.uvic.ca/learningandteaching/students/scholarships/jcura/\">Jamie Cassels\nUndergraduate Research\nAward</a>.\nIt’s given to two students from every department each year.</p>\n\n<p>In addition to $1,500 toward tuition, recipients get a $50 stipend to spend on\nposter materials for the eventual JCURA year-end fair. If you’ve ever been to a\nhigh school science fair or a college job fair, just picture that, but with a\nwider array of disciplines represented.</p>\n\n<p>Because I was not required to use my $50 stipend on printing materials\nspecifically, I didn’t. My favourite science fair projects, as a kid, were the\nones where you didn’t just read a poster. I figured I’d make something a little\nmore interactive for my visitors to deal with. So, “Why make a poem out of a\nwebsite?” That’s why.</p>\n\n<h2 id=\"whats-with-the-accompanying-essay\">What’s with the accompanying essay?</h2>\n\n<p>It’s a poemy, tongue-in-cheek window into the nature of my research. While I\nthink there’s overlap between “creative research” and “academic research,”\ncreative research doesn’t follow the same rules.</p>\n\n<p>The academic research that I’m most familiar with as a university graduate\nfeigns uncontaminatedness and objectivity toward its subject. Although academics\nmight start research out of a place of curiousity or passion, they may need to\nsquelch some enthusiasm, or their research may stay unpublished. Rightly so.\nThere’s value to that system.</p>\n\n<p>Meanwhile, creative search can start in the same place—a place of passion—but\nsprawl across disciplines and styles and remain unsquelched. See Jordan Abel’s\nbook <a href=\"http://www.jordanabel.ca/uninhabited/\"><em>Un/inhabited</em></a>, which documents\nthe colonialist language used in copyright-lapsed (read: very old) western\nnovels about land and land ownership.</p>\n\n<p>The “creative thesis” is getting more and more popular, but it still doesn’t\nhave the same clout that an “academic” thesis has. I don’t want to say that a\ncreative thesis is less legitimate, than a “non-creative” thesis, but they do\nhave a way of making uninteresting subject matter more interesting.</p>\n\n<p>My own creative research here, and the way I present that research, has less to\ndo with deep dives into external materials or studies and more to do with sleepy\nreflections on the loss of personal motivation, focus, and feeling like life\nsure is boring. I don’t want to say that my research is less legitimate, but I’d\nagree with you that it’s less interesting.</p>\n\n<h2 id=\"are-you-one-of-those-video-games-arent-art-people\">Are you one of those “video games aren’t art” people?</h2>\n\n<p>It sounds like you’re referring to the section in the essay about “gameness.” In\nit, I say that <em>Sleep when exhausted</em> falls outside of what I’d normally\nconsider a game.</p>\n\n<p>I’m not a “video games aren’t art” person. I just don’t think this is a video\ngame. You can’t really win, and the poem’s mechanics aren’t skill-based in any\nway. The mechanics—clicking through a line to get a new set of lines—are barely\neven narrative. I see the forward motion of the poem the same way that I see my\nown thought process: not focused, only somewhat linear, and attention-averse.</p>\n\n<h2 id=\"is-this-work-scrappy\">Is this work scrappy?</h2>\n\n<p>Yeah. When I started this, I had no idea how to build a branching narrative for\nthe web, and I had no idea what the poem’s content would be. I did outline some\nof it, to gauge the general trajectory, but as I was implementing the trees I\nveered quickly into doing whatever I felt like at that moment.</p>\n\n<p>I experimented with doing the whole thing in <a href=\"http://twinery.org\">Twine</a>, but I had a hard time\ngetting the non-linear, wrap-around, lost feeling using that system.</p>\n\n<p>Please, please, please don’t look at the source code for this effing thing.</p>\n\n<h2 id=\"does-this-thing-have-a-structure\">Does this thing have a structure?</h2>\n\n<p>I guess so, but I’m still not able to parse it completely. Or, making a perfect\nmap of this poem (by hand) would be quite difficult. There are <em>a lot</em> of\n“potential poems” in here, and while I’d love to see them all extracted into a\nseries of separated poems—there would be a lot of them.</p>\n\n<p>However, this thing does have a system. There are three types of states:</p>\n\n<ul>\n  <li>Observation trees (I went to the kitchen / I went to the bathroom / etc.)</li>\n  <li>Streams of consciousness (I / love / Maria)</li>\n  <li>Clarities (I was bored / /)</li>\n</ul>\n\n<p>It’s nice to have system language for what this thing is, but I don’t think it\nmakes the work any more interesting. Just jump in and see how it makes you feel.</p>\n\n<h2 id=\"wheres-this-source-code-im-not-supposed-to-look-at\">Where’s this source code I’m not supposed to look at?</h2>\n\n<p>You can find the source code <a href=\"https://github.com/benjaminwil/sleepwhen\">at this GitHub repository</a>.</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>The class is called Writing Interactive Narrative: “A workshop/seminar in writing for digital media, hyper-literature, video games, interactive installations and experiences.” <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:2\">\n      <p>I call it a “visual poem” because the white space, three-column layout, and the nature of content-forking are very central to the piece. Although I can see why someone would argue that it’s not <a href=\"https://en.wikipedia.org/wiki/Visual_poetry\">visual poetry according to the definition</a>. <a href=\"#fnref:2\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"},{"id":"https://benjaminwil.info/weblog/el-capitan-small","url":"https://benjaminwil.info/weblog/el-capitan-small","external_url":null,"title":"El Capitan Small","summary":"I made a theme for LaunchBar 6, a Mac OS X-based launcher and automation tool.","image":null,"banner_image":null,"date_published":"2015-12-26 12:00:00 -0700","date_modified":"2015-12-26 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb5d1b40>","#<Lifer::Tag:0x00007fffdb5d18c0>"],"language":"en","content_html":"<p>I made a theme for <a href=\"https://www.obdev.at/products/launchbar/index.html\">LaunchBar 6</a>, a Mac OS X-based launcher and\nautomation tool. It’s inspired by Small, the default theme for LaunchBar 5.</p>\n\n<p>It’s called El Capitan Small. <a href=\"https://github.com/benjaminwil/el-capitan-small\">See the GitHub repo</a> for more information\nand installation instructions.</p>\n\n"},{"id":"https://benjaminwil.info/weblog/sleep-when-exhausted","url":"https://benjaminwil.info/weblog/sleep-when-exhausted","external_url":null,"title":"Sleep when exhausted","summary":"The technical content of Sleep when exhausted, to anyone viewing its page source, is not by any means impressive and is c...","image":null,"banner_image":null,"date_published":"2014-03-05 12:00:00 -0700","date_modified":"2014-03-05 12:00:00 -0700","tags":["#<Lifer::Tag:0x00007fffdb5d9fc0>","#<Lifer::Tag:0x00007fffdb5d9bd8>"],"language":"en","content_html":"<p>The technical content of <em>Sleep when exhausted</em>, to anyone viewing its\npage source, is not by any means impressive and is crudely constructed.\nStill, as a product I would label foremost as poetry, I will offer here\nthat the amateurish build quality adds to the final product.</p>\n\n<h2 id=\"process\">Process</h2>\n\n<p>What I created for this project records my coming to the web browser\nas an outsider. I spoke colloquially, as a poet, using JavaScript to\nspeak to the client’s web browser in a language that the browser\nunderstands. I utilized the browser’s ability to calculate the unfolding\nnarrative efficiently, in a way that readers need not understand.</p>\n\n<p>And so, because I am a barely self-taught web developer, and still\nwanted to see the poem laid out somehow on the backend, I created much\nunnecessary work for myself. I often had to backtrack.</p>\n\n<p>This became a contemplative act in the same way that prayer is a\ncontemplative act: instead of humbling myself before the greatness and\nnonhumanness of <em>other</em>, I approached <em>other</em> as though <em>other</em> wanted\nto be spoken to as if it were humanlike. The only communicative\nbenefits, as far as I understand them, that can be observed from an act\nof prayer are in oneself; <em>other</em>’s involvement in the conversation was\nnot observable.</p>\n\n<p>A practiced web developer could find more efficient ways of creating\n<em>Sleep when exhausted</em>. Instead of inputting each state<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup> by hand, I\ncould have created a collection of data that, with simple keywords,\nwould grab any input data and automate the output. Instead I chose to\napproach the JavaScript like I do any analogue writing project:</p>\n\n<ul>\n  <li>I assume that I understand the language I will be working in well\nenough to communicate something.</li>\n  <li>I research in isolation, without input from mentors or peers until\nlater in the process.</li>\n  <li>I work linearly, one minuscule task after another.</li>\n  <li>I check for errors and mistakes and inconsistencies.</li>\n  <li>I repeat.</li>\n  <li>I disregard orthodox form and structure,</li>\n  <li>which might also mean disregarding common sense, readability, and\nusability.</li>\n  <li>I embrace the long hours and unpaid nature of my project.</li>\n  <li>I stop eating, sleeping, et cetera.</li>\n  <li>I take long walks in the middle of the night when restless.</li>\n</ul>\n\n<p>I do not mean to say that conventional web development cannot be a\ncontemplative or transcendental act. I only mean to distinguish between\nconventional web development, which I know little about, and my own\nemulation of web development as a poet in a culture of poetry steeped in\nprinted matter.<sup id=\"fnref:2\"><a href=\"#fn:2\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">2</a></sup> I also understand that many web designers,\ndevelopers, students, and other creatives work in a similar, albeit\nunhealthy, way—working more than eighty hours per week, losing sleep,\neating poorly, being obsessed, or whatever.</p>\n\n<h2 id=\"gameness\">Gameness</h2>\n\n<p>Because the reader generates new information to consume as they navigate\nthrough the speaker’s world, <em>Sleep when exhausted</em> could be closely\ncompared to <em>Choose Your Own Adventure</em>-style gamebooks, other branching\nnarrative systems, graphical point-and-click adventure games, visual\nnovels, or whatever.</p>\n\n<p>The major difference would be that <em>Sleep when exhausted</em> excludes\nactual choice, plot, and gameness.<sup id=\"fnref:3\"><a href=\"#fn:3\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">3</a></sup> Readers might view themselves as\n“players” when interacting with it, but more than usual, their choices\nhave no effect on this work’s outcome. Readers pick the details that\nthey pick, and details unveil further details as I have prescribed. The\ncontinuity is not narrative, or, because it is looping, chronological.\nIt is just a visual artifact of the speaker’s consciousness, much like\nother poems.</p>\n\n<h2 id=\"reading\">Reading</h2>\n\n<p>In avoiding gameness, I knew that my project would withdraw further into\nthe territory of poetry—a region that seems to exclude the majority of\npeople—and even the majority of writers. I wanted poets and nonpoets to\nbe able to approach this work. I created an <em>imaginary general\naudience</em>. So I worked to cater to a diverse set of readers, who have\nshort attention spans, or read more or less in the context of video\ngames, or who more or less read links acquired from their Facebook\nfeeds.</p>\n\n<p>Similarly, I did not want to alienate the “average reader”<sup id=\"fnref:4\"><a href=\"#fn:4\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">4</a></sup> or the\n“average reader of poetry” any more than usual and decided to make\n<em>Sleep when exhausted</em> seem book-like. This is my tiny attempt to trick\nthem into interacting with the work.<sup id=\"fnref:5\"><a href=\"#fn:5\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">5</a></sup></p>\n\n<p>If I ever wanted this imaginary general audience to enjoy, let alone\ninteract at all with this work, it would need to be completable in under\na minute and absorbing enough to invite readers interested in the work\nfor another read.</p>\n\n<h2 id=\"literariness\">Literariness</h2>\n\n<p>There is a girl seated in front of me, sitting next to her mother. She\nis twenty-three-ish years old. Our flight attendant passes her a glass\nof water. I watch her watching Jeremy Renner fight a wolf with his bare\nhands.</p>\n\n<p>I’ve already seen <em>The Bourne Legacy</em>, but it seems different now. I am\ntrying to scrub through my memory of the flick, figure out what events\nhave already occurred. I view this now without audio, through the crack\nbetween two airline seats. I attempt to measure the viewer’s pleasure,\nfiltered through her blonde, shoulder-length hair.</p>\n\n<p>Our flight attendant passes me a glass of orange juice with ice in it.\nIt takes a few minutes, but I finally find the dimmer to turn off my own\nin-flight multimedia station. I admit there is something about watching\na movie you have no intention of finishing because the duration of your\nflight just isn’t long enough, but today I want to just be on this\nairplane and do nothing.</p>\n\n<h2 id=\"obsolescence\">Obsolescence</h2>\n\n<p>As web browsers are perpetually modernized, support for <em>Sleep when\nexhausted</em> will likely drop, at least partially. This type of problem\naffects all digital works and will impair us from interacting with\ncontent as it was intended—at least until content creators adopt plain\ntext as <em>the</em> standard method of digitally storing and/or documenting\nhuman-readable information<sup id=\"fnref:6\"><a href=\"#fn:6\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">6</a></sup> or move back to paper.</p>\n\n<p><em>Sleep when exhausted</em> will also become visually obsolete as it ages,\nand is probably ugly already. I regret aesthetic choices that I have\nmade. That said, I do not intend to continue support for this work, and\nI welcome any obsolescence gratefully.</p>\n\n<h2>Reading list</h2>\n\n<ul>\n\t<li><a href=\"http://www.kyoolee.net/From_Modernism_to_Hypermodernism_and_Beyond_-_Interview_with_Paul_Virilio.pdf\">From Modernism to Hypermodernism and Beyond</a>. Armitage, John; Virilio, Paul</li>\n\t<li><a href=\"http://tm-resource.projects.cavi.au.dk/?page_id=1291\">Post-digital Research, vol. 3, issue 1</a>.</li>\n\t<li><a href=\"http://www.ubu.com/papers/fahlstrom01.html\">Manifesto for Concrete Poetry</a>. Fahlström, Öyvind </li>\n\t<li><a href=\"http://www.gauss-pdf.com/post/77921584015/gpdf101-matthew-fee-instructions-for-lightning\">Instructions for Lightning Avoidance</a>. Fee, Matthew</li>\n\t<li><a href=\"http://ubu.com/vp/Typewriter_Poems.html\">Typewriter Poems</a>. Finch, Peter (ed.)</li>\n\t<li><a href=\"http://raley.english.ucsb.edu/wp-content2/uploads/234/Mak.pdf\">How the Page Matters</a>. Mak, Bonnie</li>\n\t<li><a href=\"http://vispo.com/bp/introduction.htm\">First Screening</a>. bpNichol</li>\n\t<li><a href=\"http://kairos.technorhetoric.net/12.3/topoi/stolley/\">The Lo-Fi Manifesto</a>. Stolley, Karl</li>\n\t<li><a href=\"http://www.zeldman.com/2012/05/18/web-design-manifesto-2012/\">Web Design Manifesto 2012</a>. Zeldman, Jeffrey</li>\n</ul>\n\n<h2>Resources</h2>\n\n<ul>\n\t<li><a href=\"http://dash.generalassemb.ly\">Dash</a></li>\n\t<li><a href=\"http://jquery.com\">jQuery</a></li>\n\t<li><a href=\"https://github.com/lucaong/jquery-machine\">jQuery-Machine</a></li>\n\t<li><a href=\"https://daneden.me/toast/\">Toast</a></li>\n\t<li><a href=\"http://www.dafont.com/liquid-crystal.font\" title=\"Liquid Crystal\">Liquid Crystal</a></li>\n\t<li><a href=\"http://www.dafont.com/weblysleek-ui.font\" title=\"Webly Sleek\">Webly Sleek</a></li>\n</ul>\n\n<h2 id=\"acknowledgements\">Acknowledgements</h2>\n\n<p>This work was developed for and funded by the Jamie Cassels\nUndergraduate Research Awards program at the University of Victoria.\nThis project would not have been as cool without the support and\nencouragement of Tim Lilburn and Karolinka Zuzalek, with special thanks\nto Patrick Close, Matthew Hooton, Megan Jones, David Leach, Courtney\nLøberg, Garth Martens, Helen Marzolf, Jordan Soles, Valerie Tenning, and\nUVic’s personal web space.</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>By “state,” I mean any three lines that you can see at once. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:2\">\n      <p>This is a generalization about the literary culture in Victoria,\nBritish Columbia. I do not mean you any offence! <a href=\"#fnref:2\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:3\">\n      <p>I define games as objective- and choice-oriented systems, which\nare primarily unlike to the arts. I find nothing about gameness\ndistasteful, but <em>Sleep when exhausted</em> is not intended to be a\ngame. <a href=\"#fnref:3\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:4\">\n      <p>who deeply hates those awful slideshow-based articles and prefers\nto just scroll down a single webpage. <a href=\"#fnref:4\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:5\">\n      <p>For the JCURA installation, I presented the poem on an Asus Nexus\n7 as a fullscreen application generated by Google Chrome. <a href=\"#fnref:5\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n    <li id=\"fn:6\">\n      <p><em>The Lo-Fi Manifesto</em>. Stolley, Karl. <a href=\"#fnref:6\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>\n"}]}
