Congratulations!

[Valid Atom 1.0] This is a valid Atom 1.0 feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: http://www.tbray.org/ongoing/ongoing.atom

  1. <?xml version='1.0' encoding='UTF-8'?>
  2. <feed xmlns='http://www.w3.org/2005/Atom'
  3.      xmlns:thr='http://purl.org/syndication/thread/1.0'
  4.      xml:lang='en-us'>
  5. <title>ongoing by Tim Bray</title>
  6. <link rel='hub' href='http://pubsubhubbub.appspot.com/' />
  7. <id>https://www.tbray.org/ongoing/</id>
  8. <link href='https://www.tbray.org/ongoing/' />
  9. <link rel='self' href='https://www.tbray.org/ongoing/ongoing.atom' />
  10. <link rel='replies'       thr:count='101'       href='https://www.tbray.org/ongoing/comments.atom' />
  11. <logo>rsslogo.jpg</logo>
  12. <icon>/favicon.ico</icon>
  13. <updated>2024-09-06T14:44:04-07:00</updated>
  14. <author><name>Tim Bray</name></author>
  15. <subtitle>ongoing fragmented essay by Tim Bray</subtitle>
  16. <rights>All content written by Tim Bray and photos by Tim Bray Copyright Tim Bray, some rights reserved, see /ongoing/misc/Copyright</rights>
  17. <generator uri='/misc/Colophon'>Generated from XML source code using Perl, Expat, Emacs, Mysql, Ruby, Java, and ImageMagick.  Industrial-strength technology, baby.</generator>
  18.  
  19. <entry>
  20. <title>0 dependencies!</title>
  21. <link href='https://www.tbray.org/ongoing/When/202x/2024/09/04/0dependencies' />
  22. <link rel='replies'        thr:count='7'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/09/04/0dependencies#comments' />
  23. <id>https://www.tbray.org/ongoing/When/202x/2024/09/04/0dependencies</id>
  24. <published>2024-09-04T12:00:00-07:00</published>
  25. <updated>2024-09-05T19:22:39-07:00</updated>
  26. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Software' />
  27. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  28. <category scheme='https://www.tbray.org/ongoing/What/' term='Software' />
  29. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Here’s a tiny little done-in-a-couple-hours project consisting of a single static Web page and a cute little badge you     can slap on your GitHub project</div></summary>
  30. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  31.    <p>Here’s a tiny little done-in-a-couple-hours project consisting of a single static Web page and a cute little badge you
  32.    can slap on your GitHub project.</p>
  33.    <img src="https://www.tbray.org/ongoing/When/202x/2024/09/04/0dep.png" alt="0 dependencies!" />
  34.    <p>The Web site is at
  35.    <a href="https://0dependencies.dev">0dependencies.dev</a>. The badge is visible on my current open-source projects, for example
  36.    check out
  37.    <a href="https://github.com/timbray/topfew">Topfew</a> (you have to scroll down a bit).</p>
  38.    <h2 id='p-3'>Zero, you say?</h2>
  39.    <p>In recent months I keep seeing these eruptions of geek angst about the fulminating masses of dependencies squirming
  40.    under the surface of just about any software anyone uses for anything.  The most recent, and what precipitated this, was Mike
  41.    Perham’s
  42.    <a href="https://www.mikeperham.com/2016/02/09/kill-your-dependencies/">Kill Your Dependencies</a>.</p>
  43.    <p>It’s not just that dependencies are a fertile field for CVEs
  44.    (*cough* xz *cough*) and tech debt, they’re also an enemy of predictable performance.</p>
  45.    <p>Also, they’re unavoidable. When you take a dependency, often you’re standing on the shoulders of giants. (Unfortunately,
  46.    sometimes you’re standing in the shoes of clowns.)  Software is accretive and it’s a good thing that that’s OK because it’s also
  47.    inevitable.</p>
  48.    <p>In particular, don’t write your own crypto, etc. Because in software, as in life, you’re gonna have to take some
  49.    dependencies. But… how about we take less? And how about, sometimes
  50.    we strive for zero?</p>
  51.    <h2 id='p-4'>The lower you go</h2>
  52.    <p>… the closer you are to zero. So, suppose you’re writing library code. Consider these
  53.    criteria:</p>
  54.    <ul>
  55.      <li><p>It’s low-level, might be useful to a lot of apps aimed at entirely different goals.</p></li>
  56.      <li><p>Good performance is important. Actually, let me revise that: <em>predictably good</em> performance is
  57.      important.</p></li>
  58.      <li><p>Security is important.</p></li>
  59.    </ul>
  60.    <p>If you touch all three of these bases, I respectfully suggest that you try to earn this badge: 
  61.    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="110" height="20" role="img" aria-label="⓿: dependencies!">
  62.  <a target="_blank" xlink:href="https://0dependencies.dev">
  63.    <linearGradient id="s" x2="0" y2="100%">
  64.      <stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
  65.      <stop offset="1" stop-opacity=".1"/>
  66.    </linearGradient>
  67.    <clipPath id="r">
  68.      <rect width="110" height="20" rx="3" fill="#fff"/>
  69.    </clipPath>
  70.    <g clip-path="url(#r)">
  71.      <rect width="21" height="20" fill="#555"/>
  72.      <rect x="21" width="89" height="20" fill="#d1331b"/>
  73.      <rect width="110" height="20" fill="url(#s)"/>
  74.    </g>
  75.    <g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
  76.      <text aria-hidden="true" x="115" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="110">⓿</text>
  77.      <text x="115" y="140" transform="scale(.1)" fill="#fff" textLength="110">⓿</text>
  78.      <text aria-hidden="true" x="645" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="790">dependencies!</text>
  79.      <text x="645" y="140" transform="scale(.1)" fill="#fff" textLength="790">dependencies!</text>
  80.    </g>
  81.  </a>
  82.    </svg> (By the way, it’s cool that I can toss a chunk of SVG into my HTML and it Just Works. And, you can click on it.)</p>
  83.    <h2 id='p-5'>How to?</h2>
  84.    <p>First, whatever programming language you’re in, try to stay within the bounds of what comes with the language. In Go, where I
  85.    live these days, that means your <code>go.sum</code> file is empty. Good for you!</p>
  86.    <p>Second, be aggressive. For example, Go’s JSON support is known to be kind of slow and memory-hungry. That’s OK
  87.    because there are better open-source options. For
  88.    <a href="https://github.com/timbray/quamina">Quamina</a>, I rejected the alternatives and wrote
  89.    <a href="https://github.com/timbray/quamina/blob/main/flatten_json.go">my own JSON parser</a> for the hot code path.
  90.    Which, to be honest, is a pretty low bar: JSON’s grammar could be
  91.    <a href="https://en.wikipedia.org/wiki/Rice_writing">inscribed on a grain of rice</a>, or you can rely on Doug Crockford’s
  92.    <a href="https://www.json.org/json-en.html">JSON.org</a>.</p>
  93.    <p>So, get your dependencies to zero and display the badge proudly.  Or if you can’t, <em>think</em> about each of your
  94.    dependencies. Does each of them add enough value, compared to you writing the code yourself?  In particular, taking a dependency
  95.    on a huge general-purpose library for one small simple function is an antipattern.</p>
  96.    <h2 id='p-6'>What are you going to do, Tim?</h2>
  97.    <p>I’m not trying to start a movement or anything. I just made a badge, a one-page website, and a blog post.</p>
  98.    <p>If I were fanatically dedicated, <code>0dependencies.dev</code> would be database-backed with a React front-end and multiple
  99.    Kubernetes pods, to track bearers of the badge. Uh, no.</p>
  100.    <p>But, I’ll keep my eyes open. And if any particularly visible projects that you know about want to claim the badge, let me know
  101.    and maybe I’ll start a 0dependency hall of fame.</p>
  102. </div></content></entry>
  103.  
  104. <entry>
  105. <title>Q Numbers Redux</title>
  106. <link href='https://www.tbray.org/ongoing/When/202x/2024/08/28/Q-Numbers-2' />
  107. <link rel='replies'        thr:count='0'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/08/28/Q-Numbers-2#comments' />
  108. <id>https://www.tbray.org/ongoing/When/202x/2024/08/28/Q-Numbers-2</id>
  109. <published>2024-08-28T12:00:00-07:00</published>
  110. <updated>2024-09-01T08:26:43-07:00</updated>
  111. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Quamina Diary' />
  112. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  113. <category scheme='https://www.tbray.org/ongoing/What/' term='Quamina Diary' />
  114. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Back in July I wrote about     <a href='/ongoing/When/202x/2024/07/09/Q-Numbers'>Q numbers</a>, which make it possible to compare numeric values using a finite     automaton. It represented a subset of numbers as 14-hex-digit strings. In a     remarkable instance of BDD (Blog-Driven Development, obviously) Arne Hormann and Axel Wagner figured out a way to represent     <em>all 64-bit floats</em> in at most ten bytes of UTF-8 and often fewer. This feels nearly miraculous to     me; read on for heroic bit-twiddling</div></summary>
  115. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  116.    <p>Back in July I wrote about
  117.    <a href="/ongoing/When/202x/2024/07/09/Q-Numbers">Q numbers</a>, which make it possible to compare numeric values using a finite
  118.    automaton. It represented a subset of numbers as 14-hex-digit strings. In a
  119.    remarkable instance of BDD (Blog-Driven Development, obviously) Arne Hormann and Axel Wagner figured out a way to represent
  120.    <em>all 64-bit floats</em> in at most ten bytes of UTF-8 and often fewer. This feels nearly miraculous to
  121.    me; read on for heroic bit-twiddling.</p>
  122.    <h2 id='p-1'>Numbits</h2>
  123.    <p>Arne Hormann worked out how to rearrange the sign, exponent and mantissa that make up a float’s 64 bits into a
  124.    big-endian integer that you probably couldn’t do math with but you can compare for equality and ordering. Turn that into sixteen
  125.    hex digits and you’ve got automaton fuel which covers all the floats at the cost of being a little bigger.</p>
  126.    <p>If you want to admire Arne’s awesome bit-twiddling skills, look at
  127.    <a href="https://github.com/timbray/quamina/blob/main/numbits.go">numbits.go</a>. He explained to me how it works in some chat
  128.    that I can’t find, and to be honest I can’t quite look at this and remember the explanation.</p>
  129.    <pre><code>    u := math.Float64bits(f)
  130.    // transform without branching
  131.    // if high bit is 0, xor with sign bit 1 &lt;&lt; 63,
  132.    // else negate (xor with ^0)
  133.    mask := (u>>63)*^uint64(0) | (1 &lt;&lt; 63)
  134.    return numbits(u ^ mask)</code></pre>
  135.    <p><i>[Update: Arne wrote it up! See
  136.    <a href="/ongoing/When/202x/2024/08/31/QNum-Redux-Explained">Q Numbers Redux Explained</a>.]</i></p>
  137.    <p>Even when I was puzzled, I wasn’t worried because the unit tests are good; it
  138.    works.</p>
  139.    <p>Arne called these “numbits” and wrote a nice complete API for them, although Quamina just needs <code>.fromFloat64()</code>
  140.    and <code>.toUTF8()</code>.
  141.    I and Arne both thought he’d invented this, but then he discovered that the same trick was being used in the DB2 on-disk data
  142.    format years and years ago.  Still, damn clever, and I’ve urged him to make numbits into a standalone library.</p>
  143.    <h2 id='p-2'>We want less!</h2>
  144.    <p>We care about size; Among other things, the time an automaton takes to match a value is linear (sometimes worse) in its
  145.    length.
  146.    So the growth from 14 to 16 bytes made us unhappy. But, no problemo!  Axel Wagner pointed out that if you use base-128, you
  147.    can squeeze those 64 bits into ten usable bytes of UTF-8. So now we’re <em>shorter</em> than the previous iteration of Q numbers
  148.    while handling all the float64 values…</p>
  149.    <p>But wait, there’s more! Arne noticed that for purposes of equality and comparison, trailing zeroes (<code>0x0</code>, not
  150.    <code>‘0’</code>) in those 10-byte strings
  151.    are entirely insignificant and  can just be discarded. The final digit only has 1/128 chance of being zero, so maybe no big
  152.    deal. But it turns out that you do get dramatic trailing-0 sequences in positive integers, especially small ones,
  153.    which in my experience are the kinds of numbers you most often want to match.  Here’s a chart of the length of the lengths the of
  154.    numbits-based Q numbers for the integers zero through 100,000 inclusive.</p>
  155.    <table>
  156.      <tr align="center"><th><span class="th">Length</span></th><th><span class="th">Count</span></th></tr>
  157.      <tr align="center"><td>1</td><td class="count">1</td></tr>
  158.      <tr align="center"><td>2</td><td>1</td></tr>
  159.      <tr align="center"><td>3</td><td>115</td></tr>
  160.      <tr align="center"><td>4</td><td>7590</td></tr>
  161.      <tr align="center"><td>5</td><td>92294</td></tr>
  162.    </table>
  163.    <p>They’re all shorter than 5 until you get to 1,000.</p>
  164.    <p>Unfortunately, none of my benchmarks prove any performance increase because they focus on corner cases and extreme numbers;
  165.    the benefits here are to the world’s most boring numbers, namely small non-negative integers.</p>
  166.    <p>Here I am, well past retirement age, still getting my jollies from open-source bit-banging. I hope other people manage to
  167.    preserve their professional passions into later life.</p>
  168. </div></content></entry>
  169.  
  170. <entry>
  171. <title>Q Numbers Redux Explained</title>
  172. <link href='https://www.tbray.org/ongoing/When/202x/2024/08/31/QNum-Redux-Explained' />
  173. <link rel='replies'        thr:count='0'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/08/31/QNum-Redux-Explained#comments' />
  174. <id>https://www.tbray.org/ongoing/When/202x/2024/08/31/QNum-Redux-Explained</id>
  175. <published>2024-08-31T12:00:00-07:00</published>
  176. <updated>2024-09-01T08:18:25-07:00</updated>
  177. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Quamina Diary' />
  178. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  179. <category scheme='https://www.tbray.org/ongoing/What/' term='Quamina Diary' />
  180. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'><i>[The first guest post in some years. Welcome, Arne Hormann!]</i></div></summary>
  181. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  182.    <p><i>[The first guest post in some years. Welcome, Arne Hormann!]</i></p>
  183.    <p>Hi there, I'm
  184.    <a href="https://github.com/arnehormann">Arne</a>. In July, I stumbled on a
  185.    <a href="https://lobste.rs/s/6whqcn/q_numbers">lobste.rs link</a> (thanks, Carlana) that led me to
  186.    <a href="/ongoing/When/202x/2024/07/09/Q-Numbers">Tim’s article on Q Numbers</a>.
  187.    As I'm regularly working with both floating point numbers and Go, the post made me curious<span class='dashes'> —</span> I was
  188.    sure I could improve the compression scheme. I posted comments. Tim liked my idea and challenged me to create a PR.
  189.    I did the encoding but felt overwhelmed with the integration. Tim took over and merged it. And since
  190.    <a href="https://github.com/timbray/quamina/releases/tag/v1.4.0">v1.4.0 released in August
  191.    28th</a>, it's in Quamina.</p>
  192.    <p>In Tim’s
  193.    <a href="/ongoing/When/202x/2024/08/28/Q-Numbers-2">post about that change</a>, he wrote “Arne explained to me how it works in some
  194.    chat that I can’t find, and to be honest I can’t quite look at this and remember the explanation”. Well, you're reading it right
  195.    now.</p>
  196.    <h2 id='p-1'>Float64</h2>
  197.    <p>Let's first talk about the data we are dealing with here. Quamina operates on JSON. While no JSON specification limits
  198.    numbers to
  199.    <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">IEEE 754 floating point</a> (Go calls
  200.    them <code>float64</code>),
  201.    <a href="https://datatracker.ietf.org/doc/html/rfc8259#section-6">RFC 8259 recommends</a> treating them as such.</p>
  202.    <p>They look like this:</p>
  203.    <ul>
  204.      <li><p>1 bit sign; 0 is positive, 1 is negative.</p></li>
  205.      <li><p>11 bits exponent; It uses a bias of <code>1023</code> (<code>(1&lt;&lt;10)-1</code>), and all exponent bits set means Infinity or Not a Number
  206.      (<code>NaN</code>)</p></li>
  207.      <li><p>1 mantissa high bit (implicit, never stored: <code>0</code> if all exponent bits are <code>0</code>, otherwise <code>1</code>). This is required so
  208.      there's exactly one way to store each number.</p></li>
  209.      <li><p>52 explicit mantissa bits. The 53 mantissa bits are the binary digits of the number itself.</p></li>
  210.    </ul>
  211.    <p>Both <code>0</code> and <code>-0</code> exist and are equal but are represented differently. We have to normalize <code>-0</code> to <code>0</code> for comparability,
  212.    but according to Tim’s tests, <code>-0</code> cannot occur in Quamina because JSON decoding silently converts <code>-0</code> to <code>0</code>.</p>
  213.    <p>With an exponent with all bits set, Infinity has a mantissa of <code>0</code>. Any other mantissa is NaN. But both sign values are
  214.    used. There are a lot of different NaNs; <code>1&lt;&lt;53 - 2</code> different ones!</p>
  215.    <p>In JSON, Infinity and NaN are not representable as numbers, so we don't have to concern ourselves with them.</p>
  216.    <p>Finally, keep in mind that these are binary numbers, not decimals. Decimal <code>0.1</code> cannot be accurately encoded. But <code>0.5</code>
  217.    can. And all integers up to <code>1&lt;&lt;53</code>, too.</p>
  218.    <h2 id='p-2'>Adding numbers to Quamina</h2>
  219.    <p>Quamina operates on UTF-8 strings and compares them byte by byte. To add numbers to it, they have to be bytewise-comparable
  220.    and all bytes have to be valid in UTF-8.</p>
  221.    <p>Given these constraints, let's consider the problem of comparability, first.</p>
  222.    <h2 id='p-3'>Sortable bits</h2>
  223.    <p>We can use <code>math.Float64bits()</code> to convert a <code>float64</code> into its individual bits (stored as <code>uint64</code>).</p>
  224.    <p>Positive numbers are already perfectly sorted. But they are smaller than negative numbers. To fix that, we always flip the
  225.    sign bit so it's <code>1</code> for positive and <code>0</code> for negative values.</p>
  226.    <p>Negative values are sorted exactly the wrong way around. To totally reverse their order, we have to flip all exponent and
  227.    mantissa bits in addition to the sign bits.</p>
  228.    <p>A simple implementation would look like:</p>
  229.    <pre><code>
  230. func numbitsFromFloat64(f float64) numbits {
  231. u := math.Float64bits(f)
  232. if f &lt; 0 {
  233. return numbits(^u)
  234. }
  235. return numbits(u) | (1 &lt;&lt; 63)
  236. }
  237. </code></pre>
  238.    <p>Now let's look at the actual code:</p>
  239.    <pre><code>
  240. func numbitsFromFloat64(f float64) numbits {
  241. u := math.Float64bits(f)
  242. mask := (u>>63)*^uint64(0) | (1 &lt;&lt; 63)
  243. return numbits(u ^ mask)
  244. }</code></pre>
  245.    <p>The <code>mask</code> line can be a bit of a headscratcher...</p>
  246.    <ol>
  247.      <li><p><code>u>>63</code> moves the sign bit of the number to the lowest bit</p></li>
  248.      <li><p>the result will be <code>0</code> for positive values and <code>1</code> for negative values</p></li>
  249.      <li><p>that's multiplied with <code>^0</code> - all 64 bits set to true</p></li>
  250.      <li><p>we now have <code>0</code> for positive numbers and all bits set for negative numbers</p></li>
  251.      <li><p>regardless, always set the sign bit with <code>| (1 &lt;&lt; 63)</code></p></li>
  252.    </ol>
  253.    <p>By xoring <code>mask</code> to the original bits, we get our transformation for lexically ordered numbers.</p>
  254.    <p>The code is a bit hard to parse because it avoids branches for performance reasons.</p>
  255.    <h2 id='p-4'>Sortable bytes</h2>
  256.    <p>If we were to use the uint64 now, it would work out great. But it has to be split into its individual bytes. And on little
  257.    endian systems - most of the frequently used ones - the byte order will be wrong and has to be reversed. That's done by storing
  258.    the bytes in big endian encoding.</p>
  259.    <h2 id='p-5'>UTF-8 bytes</h2>
  260.    <p>Our next problem is the required UTF-8 encoding. Axel suggested to only use the lower 7 bits. That means we need up to 10 byte instead of 8 (<code>7*10 = 70</code> fits <code>8*8 = 64</code>).</p>
  261.    <h2 id='p-6'>Compress</h2>
  262.    <p>The final insight was that trailing <code>0</code> bytes do not influence the comparison at all and can be dropped. Which compresses
  263.    positive power-of-two numbers and integers even further. Not negative values, though - the required bit inversion messes it
  264.    up.</p>
  265.    <p>And that's all on this topic concerning Quamina<span class='dashes'> —</span> even if there's so, so much more about floats.</p>
  266. </div></content></entry>
  267.  
  268. <entry>
  269. <title>Mozart Requiem</title>
  270. <link href='https://www.tbray.org/ongoing/When/202x/2024/08/25/Mozart-Requiem' />
  271. <link rel='replies'        thr:count='4'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/08/25/Mozart-Requiem#comments' />
  272. <id>https://www.tbray.org/ongoing/When/202x/2024/08/25/Mozart-Requiem</id>
  273. <published>2024-08-25T12:00:00-07:00</published>
  274. <updated>2024-08-25T16:37:08-07:00</updated>
  275. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts/Music' />
  276. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts' />
  277. <category scheme='https://www.tbray.org/ongoing/What/' term='Music' />
  278. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Audio' />
  279. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  280. <category scheme='https://www.tbray.org/ongoing/What/' term='Audio' />
  281. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Vancouver has many choirs, with differing proficiency levels and repertoire     choices. Most gather fall-to-spring and take the summer off. Thus,     <a href='https://www.facebook.com/SummerChor/'>Summerchor</a>, which aggregates a couple of hundred singers from many choirs to     tackle one of the Really Big choral pieces each August. This year it was the     <a href='https://en.wikipedia.org/wiki/Requiem_(Mozart)'>Mozart Requiem</a>. Mozart died while writing this work and there are     many “completions” by other composers. Consider just     <a href='https://en.wikipedia.org/wiki/Modern_completions_of_Mozart%27s_Requiem'>the Modern completions</a>; this performance     was of      <a href='https://en.wikipedia.org/wiki/Modern_completions_of_Mozart%27s_Requiem'>Robert Levin</a>’s</div></summary>
  282. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  283.    <p>Vancouver has many choirs, with differing proficiency levels and repertoire
  284.    choices. Most gather fall-to-spring and take the summer off. Thus,
  285.    <a href="https://www.facebook.com/SummerChor/">Summerchor</a>, which aggregates a couple of hundred singers from many choirs to
  286.    tackle one of the Really Big choral pieces each August. This year it was the
  287.    <a href="https://en.wikipedia.org/wiki/Requiem_(Mozart)">Mozart Requiem</a>. Mozart died while writing this work and there are
  288.    many “completions” by other composers. Consider just
  289.    <a href="https://en.wikipedia.org/wiki/Modern_completions_of_Mozart%27s_Requiem">the Modern completions</a>; this performance
  290.    was of
  291.    <a href="https://en.wikipedia.org/wiki/Modern_completions_of_Mozart%27s_Requiem">Robert Levin</a>’s.</p>
  292.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/25/PXL_20240825_020725834.png" alt="Mozart’s Requiem performed in St. Andrews-Wesley" />
  293.    <div class='caption'><p>Summerchor performs Mozart’s <cite>Requiem</cite> in<br/>
  294.    <a href="https://standrewswesley.com">St.Andrews-Wesley United Church</a>, August 24, 2024.</p></div>
  295.    <p>The 200 singers were assisted by four soloists, a piano, a trombone, the church’s excellent pipe organ, and finally, of
  296.    course, by the towering arched space.</p>
  297.    <p>The combined power of Mozart’s music, the force of massed voices, and the loveliness of the great room yielded a
  298.    entirely overwhelming torrent of beauty. I felt like my whole body was being squeezed.</p>
  299.    <p>Obviously, in an hour-long work, some parts are stronger than others. For me, the opening <i>Requiem Aeternum</i> and
  300.    <i>Kyrie</i> hit hard, then the absolutely wonderful ascending line opening the <i>Domine Jesu</i> totally crushed me.
  301.    But for every one of the three-thousand-plus seconds, I was left in no doubt that I was experiencing about as much beauty as
  302.    a human being can.</p>
  303.    <h2 id='p-1'>God?</h2>
  304.    <p>We were in a house of worship. The words we were listening to were liturgical, excerpted from Scripture. What, then, of the
  305.    fact that
  306.    <a href="/ongoing/When/202x/2022/08/24/On-Faith">I am actively hostile</a> to religion? Yeah, I freely acknowledge that all
  307.    this beauty I’m soaking up is founded on faith. Other people’s faith, of other times. The proportion of people who profess that
  308.    (or any) faith is monotonically declining, maybe not everywhere, but certainly where I live.</p>
  309.    <p>Should I feel sad about that?
  310.    Not really; The fact that architects and musicians worked for the Church is related to the fact that the Church was willing to
  311.    pay. Musicians can manage without God, generally, as long as they’re getting paid.</p>
  312.    <h2 id='p-2'>The sound</h2>
  313.    <p>We’ve been going out to concerts quite a lot recently so of course I’ve been
  314.    <a href="/ongoing/What/Arts/Music/">writing about it</a>, and usually discussing the sound quality too.</p>
  315.    <p>The sound at the <cite>Requiem</cite> was beyond awesome. If you look at the picture above you can see there’s a soundboard
  316.    and a guy sitting at it, but I’m pretty sure the only boost was on the piano, which had to compete with 200 singers and the
  317.    organ. So, this was the usual classical-music scenario: If you want dynamic range, or to hear soloists, or to blend parts, you
  318.    do that with musical skill and human throats and fingers and a whole lot of practice. There’s no knob to twirl.</p>
  319.    <p>I mean,
  320.    <a href="/ongoing/When/202x/2024/05/26/TTB">I love well-executed electric sound</a>, but large-scale classical, done well, is on
  321.    a whole other level.</p>
  322.    <p>Above, I mentioned the rising line at the opening of the <cite>Domine Jesu</cite>; the pulses, and the space between them,
  323.    rose up in the endless vertical space as they rose up the scale, and yet were clearly clipped at start and end, because you
  324.    don’t get that much reverb
  325.    when the pews are full of soft human flesh and the roof is made of old wood, no matter how big the church is. I just don’t have
  326.    words for how wonderful it sounded.</p>
  327.    <h2 id='p-3'>Classical?</h2>
  328.    <p>Obviously, this is what is conventionally called “classical” music. But I’m getting a little less comfortable with that term,
  329.    especially the connotation that it’s “music for old people” (even though I am one of those). Because so is
  330.    <a href="/ongoing/When/202x/2024/05/26/TTB">rootsy rock music</a> and
  331.    <a href="/ongoing/When/202x/2024/08/11/Countrywomen">bluegrass and Americana</a> and
  332.    <a href="/ongoing/When/202x/2024/06/23/Lounge-Penguin">GoGo Pengin</a> and
  333.    <a href="/ongoing/When/202x/2023/10/17/Rock-Tech">Guns N’ Roses</a>.</p>
  334. </div></content></entry>
  335.  
  336. <entry>
  337. <title>2024 Pollscrolling</title>
  338. <link href='https://www.tbray.org/ongoing/When/202x/2024/08/20/2024-Election-Junky' />
  339. <link rel='replies'        thr:count='2'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/08/20/2024-Election-Junky#comments' />
  340. <id>https://www.tbray.org/ongoing/When/202x/2024/08/20/2024-Election-Junky</id>
  341. <published>2024-08-20T12:00:00-07:00</published>
  342. <updated>2024-08-20T17:07:32-07:00</updated>
  343. <category scheme='https://www.tbray.org/ongoing/What/' term='The World/Politics' />
  344. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  345. <category scheme='https://www.tbray.org/ongoing/What/' term='Politics' />
  346. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>The 2024 US election has, in the last few weeks, become the most interesting one I can recall. I’m pretty old, so that’s a     strong statement; I can recall     a <em>lot</em> of US elections. The Internet makes it way too easy to obsess over a story that’s this big and has this many     people sharing opinions. Here is my opinion, not on who’s winning, but on how, with only a very moderate expenditure of time and     money, you can be as well-informed as anybody in the world as to how it’s going</div></summary>
  347. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  348.    <p>The 2024 US election has, in the last few weeks, become the most interesting one I can recall. I’m pretty old, so that’s a
  349.    strong statement; I can recall
  350.    a <em>lot</em> of US elections. The Internet makes it way too easy to obsess over a story that’s this big and has this many
  351.    people sharing opinions. Here is my opinion, not on who’s winning, but on how, with only a very moderate expenditure of time and
  352.    money, you can be as well-informed as anybody in the world as to how it’s going.</p>
  353.    <p>Disclosures: I’m not American, got no vote on this one. Am left of the US Democratic party, but at this point they represent
  354.    an infinitely better option for America than does anything connected to Donald Trump. Thus, the following remarks should be
  355.    assumed to have a strong Harris/Walz bias.</p>
  356.    <p>I claim that using the following sites should, in 5-15 minutes a day, give you an understanding of the state of the
  357.    race that is very close to that of the big-name prognosticators writing in the big-name publications.</p>
  358.    <h2 id='p-1'>Polls generally</h2>
  359.    <p>They’ve been wrong a lot recently. The industry is still trying to complete the transition off landlines, which few people
  360.    have any more; those who still do are an entirely unrepresentative sample. I’ve seen a few smart people guessing that pollers
  361.    may be getting better, this cycle. We’ll see, won’t we?</p>
  362.    <h2 id='p-2'>Prognosticators generally</h2>
  363.    <p>They suck. The arm-waving, gut-feel bullshit, and undisclosed bias is disgusting. In the pages of the really big
  364.    properties like the NYT and WaPo, the opinion columnists are mostly partisan hacks looking for reasons to explain why their
  365.    favored party is doing just fine and the other is failing. I’ve pretty well given up reading them.</p>
  366.    <p>OK, now let’s get to our sources, in no particular order.</p>
  367.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/20/TPM.png" alt="Talking Points Memo" />
  368.    <h2 id='p-3'>Talking Points Memo</h2>
  369.    <p><a href="https://talkingpointsmemo.com">TPM</a>
  370.    is the home of Josh Marshall, the ur-blogger on US Politics, and still as good as anyone.
  371.    He’s hired a bunch of other clear and clear-eyed writers, who obsess about elections all day every
  372.    day. They have a strong and acknowledged pro-Democratic and anti-Trump bias, but in my opinion don’t let it
  373.    clutter their analyses. If you’re reading the polling sites
  374.    that I’m recommending below, <cite>TPM</cite> will have smart interpretive pieces about what they might mean.</p>
  375.    <p>A lot of their stuff is free, but the best isn’t. Unfortunately, they only offer annual subscriptions at US$70; I’ve
  376.    subscribed for many years. It depends on how fierce the election monkey on <em>your</em> back is, but in my
  377.    personal experience, there is no other site that offers more depth and clarity on US politics. Maybe worth your money for one
  378.    year, this year.</p>
  379.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/20/Silver.png" alt="Silver Bulletin" />
  380.    <h2 id='p-4'>Nate Silver</h2>
  381.    <p>The former <cite>538</cite> guy is now at the
  382.    <a href="https://www.natesilver.net">Silver Bulletin</a>. Nate is not everyone’s cup of tea, but he retained the IP rights to
  383.    the 538 election model, which is updated on a daily basis.  He admits to being moderately pro-Harris this time around but argues
  384.    convincingly that he doesn’t let this cloud his analysis, which I generally find pretty cogent.
  385.    You probably need a little bit of statistical literacy to fully  appreciate this stuff.</p>
  386.    <p>As of today, August 20, 2024, his probability-of-win numbers are Harris 53.6%, Trump 45.7%.</p>
  387.    <p>The <cite>Silver Bulletin</cite> has some free stuff, but the best parts, including the model updates, are paywalled. The price is
  388.    currently $14/month, but on September 1st they’re going up to $20, just until the election is over. Because a lot of people like
  389.    me signed up with every expectation of unsubscribing in three months.</p>
  390.    <p>If you happen to care about professional sports there’s lots of brain candy there too.</p>
  391.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/20/538.png" alt="538 Poll Report" />
  392.    <h2 id='p-5'>538</h2>
  393.    <p>Their
  394.    <a href="https://projects.fivethirtyeight.com/polls/">Latest Polls</a> page is now part of ABC news but seems to retain many of
  395.    the virtues that made 538 the flavor-of-the-month a few years ago.</p>
  396.    <p>The crucial thing, if you’re visiting once a day, is to find the “Sort by Date” widget and click on “Added”, which brings the
  397.    most recent stuff that you probably haven’t seen yet to the top.</p>
  398.    <p>As I write this, their national polling average has Harris 46.6%, Trump 43.8%. This is quite different from Silver’s
  399.    “probability of winning”. 538’s main virtue is that they get the polls up about as fast as anyone else. It’s free.</p>
  400.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/20/RCP.png" alt="RealClearPolitics" />
  401.    <h2 id='p-6'>RCP</h2>
  402.    <p>I kind of hate to mention <a href="https://www.realclearpolitics.com">RealClearPolitics</a> because it is at least in part a
  403.    hive of filthy MAGA-friendly screamers. Their front page is all links, MAGA-dominated but including a
  404.    sprinkling of analysis from more even-handed or openly-progressive sources. Anyhow, the problem with that stuff isn’t the bias,
  405.    it’s the fact that they’re just a bunch of low-value prognosticators. I wouldn’t waste much time on the front page, I’d start by
  406.    clicking on “Polls”, near the top left.</p>
  407.    <p>Their aggregation of poll results will contain about what you’ll see at 538 (sometimes important polls get to one place
  408.    first, sometimes the other). But RCP offers other useful resources. There is the
  409.    <a href="https://www.realclearpolitics.com/rcp-pollster-scorecard/">RCP Pollster Scorecard</a>, which offers data on the
  410.    accuracy and bias of most of the pollers whose results they report. Since some of those pollers are super extra biased, this can
  411.    be a useful sanity check.</p>
  412.    <p>What I really like is the
  413.    <a href="https://www.realclearpolling.com/maps/president/2024/no-toss-up/electoral-college">Electoral College Map</a>, which as
  414.    I write is predicting a Trump victory, 287-251 in EC votes. You can click on each state and see the polls they used to compute
  415.    their prediction for that state.</p>
  416.    <p>I think their MAGA bias shows in the predictions, but that’s OK, because there’s a “Create Your Own Map” link, where
  417.    you can disagree with them and explore each side’s path to victory or defeat. Looking at today’s map, my conclusion is that if
  418.    Harris can flip Pennsylvania from red to blue she probably wins, and if she can bring along either or both of Arizona and North
  419.    Carolina, Trump is roadkill.</p>
  420.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/20/CNN.png" alt="CNN" />
  421.    <h2 id='p-7'>CNN</h2>
  422.    <p>No, really. It’s
  423.    <a href="https://www.cnn.com">cheesy and overhyped</a> but feels to me like it’s speaking to a pretty big constituency that I
  424.    don’t know anybody from, there’s a bit of <i>zeitgeist</i> in the flow. To my eye it leans a little more Dem than GOP (that’s a
  425.    surprise) and is not actually terrible.</p>
  426.    <h2 id='p-8'>When?</h2>
  427.    <p>My advice is to wait until at least mid-afternoon, when the polls of the day have been published and ingested, then put in
  428.    your pollscrolling time. Won’t take too long and you’ll know what the allegedly-smart people know.</p>
  429. </div></content></entry>
  430.  
  431. <entry>
  432. <title>Basic Infrastructure</title>
  433. <link href='https://www.tbray.org/ongoing/When/202x/2024/08/13/Basic-Infrastructure' />
  434. <link rel='replies'        thr:count='5'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/08/13/Basic-Infrastructure#comments' />
  435. <id>https://www.tbray.org/ongoing/When/202x/2024/08/13/Basic-Infrastructure</id>
  436. <published>2024-08-13T12:00:00-07:00</published>
  437. <updated>2024-08-13T14:44:33-07:00</updated>
  438. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Cloud' />
  439. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  440. <category scheme='https://www.tbray.org/ongoing/What/' term='Cloud' />
  441. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Recently, I was looking at the infrastructure bills for our     <a href='https://cosocial.ca'>CoSocial</a> co-op member-owned Mastodon instance, mostly Digital Ocean and a bit of AWS. They seemed     too high for what we’re getting. Which makes me think about the kind of infrastructure that a decentralized social network     needs, and how to get it</div></summary>
  442. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  443.    <p>Recently, I was looking at the infrastructure bills for our
  444.    <a href="https://cosocial.ca">CoSocial</a> co-op member-owned Mastodon instance, mostly Digital Ocean and a bit of AWS. They seemed
  445.    too high for what we’re getting. Which makes me think about the kind of infrastructure that a decentralized social network
  446.    needs, and how to get it.</p>
  447.    <p>I worked at AWS for 5½ years and part of my job was explaining why public-cloud infrastructure is a good idea. I had no
  448.    trouble doing that because, for the people who are using it, it <em>was</em> (and is) a good idea. The public cloud offers a quality of
  449.    service, measured by performance, security, and durability, that most customers couldn’t build by themselves.
  450.    One way to put it is this: If you experience problems in those areas, they are much more likely to be problems in your software
  451.    than in the cloud infrastructure.</p>
  452.    <p>Of course, providing this level of service costs billions in capex and salaries for thousands of expensive senior
  453.    engineers. So you can expect your monthly cloud-services bill to be substantial.</p>
  454.    <h2 id='p-1'>But what if…</h2>
  455.    <p>What if you don’t need that quality of service?  What if an hour of downtime now and then was an irritant but not an
  456.    existential problem? What if you were OK with occasionally needing to restore data from backup? What if everything on your
  457.    server was public data and not interesting to bad actors?</p>
  458.    <p>Put another way, what if you were running a small-to-medium Fediverse instance?</p>
  459.    <p>If it goes offline occasionally, nobody’s life is damaged much. And, while I grant that this is not well-understood, at this
  460.    point in time everything on Fedi should be considered public, and I don’t think that’ll change even when we get end-to-end
  461.    encryption because that data of course isn’t plain text. Here is what you care about:</p>
  462.    <ol>
  463.      <li><p>Members’ posts don’t get permanently lost.</p></li>
  464.      <li><p>You don’t want bad people hijacking your members’ accounts and posting damaging stuff.</p></li>
  465.      <li><p>You don’t want to provision and monitor a relational database.</p></li>
  466.    </ol>
  467.    <h2 id='p-2'>“Basic”?</h2>
  468.    <p>So, what I want for decentralized social media is computers and storage “in the cloud”, as in I don’t want to have to visit them
  469.    physically. But I don’t need them to be very fast or to be any more reliable than modern server and disk hardware generally are. I do
  470.    need some sort of effective backup/restore facility, and I want good solid modern authentication.</p>
  471.    <p>And, of course, I want this to be a whole lot cheaper than the “enterprise”-facing public cloud. Because I’m not an
  472.    enterprise.</p>
  473.    <p>(I think I still need a CDN. But that’s OK because they’re commoditized and competitive these days.)</p>
  474.    <p>I know this is achievable. What I don’t know is who might want to offer this kind of infrastructure. I think some of it is
  475.    already out there, but you have to be pretty savvy about knowing who the vendors are and their product ranges and strengths and
  476.    weaknesses.</p>
  477.    <p>Maybe we don’t need any new products, just a new product category, so people like me know which products to look at.</p>
  478.    <p>How about “Basic Infrastructure”?</p>
  479. </div></content></entry>
  480.  
  481. <entry>
  482. <title>Countrywomen</title>
  483. <link href='https://www.tbray.org/ongoing/When/202x/2024/08/11/Countrywomen' />
  484. <link rel='replies'        thr:count='0'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/08/11/Countrywomen#comments' />
  485. <id>https://www.tbray.org/ongoing/When/202x/2024/08/11/Countrywomen</id>
  486. <published>2024-08-11T12:00:00-07:00</published>
  487. <updated>2024-08-11T12:00:00-07:00</updated>
  488. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts/Music' />
  489. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts' />
  490. <category scheme='https://www.tbray.org/ongoing/What/' term='Music' />
  491. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Audio' />
  492. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  493. <category scheme='https://www.tbray.org/ongoing/What/' term='Audio' />
  494. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>In the last couple of weeks I’ve been at shows by     <a href='https://www.mollytuttlemusic.com'>Molly Tuttle</a> and     <a href='https://www.sierraferrellmusic.com'>Sierra Ferrell</a> (I recommend clicking both those     links just for the front-page portraits). Herewith thoughts on the genres, performances, and sound quality</div></summary>
  495. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  496.    <p>In the last couple of weeks I’ve been at shows by
  497.    <a href="https://www.mollytuttlemusic.com">Molly Tuttle</a> and
  498.    <a href="https://www.sierraferrellmusic.com">Sierra Ferrell</a> (I recommend clicking both those
  499.    links just for the front-page portraits). Herewith thoughts on the genres, performances, and sound quality.</p>
  500.    <p>Tuttle is post-bluegrass and Ferrell is, um, well, Wikipedia says “folk, bluegrass, gypsy jazz, and Latin styles” which, OK, I
  501.    guess, but it doesn’t mention pure old-fashioned country, her strongest flavor. These days, “Americana” is used to
  502.    describe both these artists. The notion that Americana implies “by white people” is just wrong, check out Rhiannon Giddens’
  503.    <a href="https://www.youtube.com/watch?v=RiP8Tfa8bB8">charming video</a> on the origin of the banjo. (Ms Giddens is a goddess;
  504.    if you don’t know about her, check her out.)</p>
  505.    <p>Both bands (for brevity, just Molly and Sierra) feature mandolin, fiddle, stand-up bass, and acoustic guitar. Molly adds
  506.    banjo, Sierra drums and
  507.    occasional electric guitar. Both offer flashy instrumental displays; Molly adds
  508.    big group meltdowns, veering into jam-band territory. Both women sing divinely and the bands regularly contribute lovely
  509.    multi-part harmonies.</p>
  510.    <p>I think that Americana just now is one of the most interesting living musical directions. These artists are young, are
  511.    standing on firm foundations, and are pushing into new territory. Judging by the crowds these days I’m not alone, so for
  512.    those who agree, I’ll offer a few words on each performance.</p>
  513.    <h2 id='p-1'>Molly Tuttle and Golden Highway at the Hollywood Theatre</h2>
  514.    <p>Interestingly, this is the same venue where I first saw Sierra, back in March of 2022. It’s intimate and nice-looking and has
  515.    decent sound.</p>
  516.    <p>The crowd was pretty grey-haired; the previous week we’d taken in an Early Music Vancouver concert dedicated to
  517.    <a href="https://en.wikipedia.org/wiki/Giovanni_Gabrieli">Gabrieli</a> (1557-1612) and the age demographic wasn’t that
  518.    different, except for Molly’s fans wear jeans and leather and, frequently, hippie accoutrements.
  519.    It dawns on me that bluegrass is in some respects a “classical” genre; It has lots of rules
  520.    and formalisms and an absolute insistence on virtuosic skill.</p>
  521.    <p>She played
  522.    <a href="https://www.setlist.fm/setlist/molly-tuttle-and-golden-highway/2024/hollywood-theatre-vancouver-bc-canada-3355fc45.html">a
  523.    generous selection of favorites</a> (<cite>El Dorado</cite>, <cite>Dooley’s Farm</cite>, <cite>Crooked Tree</cite>) and
  524.    exceptionally tasty covers (<cite>Dire Wolf</cite>, <cite>She’s a Rainbow</cite>).  The band was awesomely tight and Molly was
  525.    in fine form.</p>
  526.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/11/PXL_20240802_053730514.png" alt="Molly Tuttle and Golden Highway" />
  527.    <p>In most pictures of Molly she has hair, but during her concerts she usually tells the story of how as a young child she had
  528.    Alopecia universalis (total all-body hair loss) and, particularly if the concert venue is warm, whips off her wig. At this show
  529.    she talked about how, on behalf of a support organization, she’d visited a little
  530.    Vancouver girl with Alopecia, and how sad she was that the kid couldn’t come to the show since the Hollywood is also a bar. It
  531.    was touching; good on her.</p>
  532.    <p>Molly, a fine singer and songwriter, is also a virtuoso bluegrass guitar flat-picker and her band are all right up
  533.    there, so the playing on balance was probably a little finer than Sierra’s posse offered. And as I mentioned, they do the
  534.    occasional jam-band rave-up, which I really enjoyed.</p>
  535.    <p>But their sound guy needs to be fired. I was at the show alone and thus found a corner to prop myself up that happened
  536.    to be right
  537.    behind this bozo’s desk. He had a couple of devices that I didn’t recognize, with plenty of sliders, physical and on-screen, and
  538.    he was hard at work from end to end “enhancing” the sound. He threw oceans of echo on Molly’s voice then yanked it out,
  539.    injected big rumble on song climaxes,
  540.    brightened up the banjo and mandolin so they sounded like someone driving nails into metal, and slammed the balance back and
  541.    forth to create fake stereo when licks were being traded. This sort of worked when they were doing the extended-jam thing,
  542.    but damaged every song that relied on sonic truth or subtlety, which was most of them. Feaugh. Concert sound people
  543.    should get out of the fucking way and reproduce what the musicians are playing. I guess Molly must like this or she wouldn’t
  544.    have hired him? I wish she could come out and hear what it sounds like though.</p>
  545.    <p>Anyhow, it’s a good band that plays good songs with astonishing skill. If you’re open to this kind of music you’d enjoy their
  546.    show.</p>
  547.    <p>The last encore was <cite>Helpless</cite>. I’m
  548.    not 100% sure that Molly knew what she was in for. Every grey-haired Canadian knows that tune and every word of its lyrics. So
  549.    as soon as she was three words in, the whole audience was booming along heartily, having a fine time. Quite a few grizzled
  550.    cheeks were wet with tears, but I thought Molly looked a little taken aback. She went with it, and it was lovely.</p>
  551.    <h2 id='p-2'>Sierra Ferrell at the Orpheum</h2>
  552.    <p><a href="https://en.wikipedia.org/wiki/Orpheum_(Vancouver)">This hall</a> is one of Vancouver’s two big venues where the
  553.    symphony plays, operas are presented, and so on. It opened in 1927 and the decor is lavish, tastefully over-the-top, but ignore
  554.    the execrable ceiling art.</p>
  555.    <img src="https://www.tbray.org/ongoing/When/202x/2024/08/11/PXL_20240811_043529266.png" alt="Sierra Ferrell" />
  556.    <div class='caption'><p>Sierra Ferrell, singing <cite>Whispering Waltz</cite>.</p></div>
  557.    <p>On this picture, my usually-trusty Pixel 7 failed me. The focus is unacceptably bad but I’m
  558.    running it anyhow to share Sierra’s outfit, which is as always fabulous. She kicked up her heels once or twice, revealing big
  559.    tall Barbie-pink boots under that dress.</p>
  560.    <p>The audience had plenty of greybeards but on balance was way younger than Molly’s, with a high proportion of women dressed
  561.    to the nines in Western-wear finery and some of the prettiest dresses I’ve seen in years.  It was really a lot of fun just
  562.    to look around and enjoy the shapes that Sierra’s influence takes.</p>
  563.    <p>Sierra is a wonderful singer but those songs, wow, I’m sure some of them will be loved
  564.    and shared long after I and she are in the grave.
  565.    <a href="https://www.setlist.fm/setlist/sierra-ferrell/2024/the-orpheum-vancouver-bc-canada-5355c709.html">Her set</a> didn’t
  566.    leave out any of the favorites. There were a few covers, notably <cite>Me and Bobby McGee</cite>, which was heartbreaking
  567.    and then rousing. Before starting Sierra acknowledged her debt to Janis Joplin, whom I never saw, but I felt Janis there in spirit.</p>
  568.    <p>Everybody is going to have a few favorites among her songs. The three-song sequence, <cite>Lighthouse</cite>, <cite>The
  569.    Sea</cite>, and <cite>Far Away Across the Sea</cite>, was so beautiful it left me feeling emptied. They turned <cite>Far
  570.    Away</cite> into a rocker with a bit of extended jamming and it was just wonderful.</p>
  571.    <p>But the thing about a Sierra Ferrell show isn’t just the songs or the singing or the playing, it’s
  572.    her million watts of charisma, and the connection with the crowd. People kept bringing her floral garlands and, after “Garden”,
  573.    someone ran up to the stage with a little potted plant.  There are some people who, when they get up on the stage, you just
  574.    can’t take your eyes off them, and she’s one of those. I’m pretty confident that if she keeps holding it together and writing
  575.    those songs, she’s headed for Dolly Parton territory in terms of fame and fortune.</p>
  576.    <p>Any complaints? Yes, this was the first stop on a new tour and the sound was initially pretty rough, but they got it fixed up
  577.    so that’s forgivable.
  578.    There’s still a problem: When Sierra
  579.    leans into a really big note she overloads whatever mike they’re using; not sure what the cure is for that.</p>
  580.    <p>Another gripe: Sierra used to have a part of the set where the band gathered around an old-school radio mike with
  581.    acoustic instruments and played in a very traditional style. I think she shouldn’t leave that out.</p>
  582.    <p>Finally, one more problem: Vancouver loves Sierra just a little too much. Every little vocal flourish, every cool little
  583.    instrumental break, every one of those got a huge roar of approval from the crowd, which, fine, but some of those songs take the
  584.    level way down and then back up again in a very artful way, and I wished the crowd would shut up, let Sierra drive, and clap at the
  585.    end of the song.</p>
  586.    <h2 id='p-3'>Americana</h2>
  587.    <p>Like I said, this is where some of the most interesting living artists are digging in and doing great work. Highly recommended.</p>
  588. </div></content></entry>
  589.  
  590. <entry>
  591. <title>Invisible Attackers</title>
  592. <link href='https://www.tbray.org/ongoing/When/202x/2024/07/30/Invisible-Attackers' />
  593. <link rel='replies'        thr:count='5'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/07/30/Invisible-Attackers#comments' />
  594. <id>https://www.tbray.org/ongoing/When/202x/2024/07/30/Invisible-Attackers</id>
  595. <published>2024-07-30T12:00:00-07:00</published>
  596. <updated>2024-08-03T08:10:15-07:00</updated>
  597. <category scheme='https://www.tbray.org/ongoing/What/' term='The World/Social Media' />
  598. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  599. <category scheme='https://www.tbray.org/ongoing/What/' term='Social Media' />
  600. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>In the last few days we’ve had an outburst of painful, intelligent, useful conversation about racism and abuse in the world     of Mastodon and the Fediverse.  I certainly learned things I hadn’t known, and I’m going to     walk you through the recent drama and toss in ideas on how to improve safety</div></summary>
  601. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  602.    <p>In the last few days we’ve had an outburst of painful, intelligent, useful conversation about racism and abuse in the world
  603.    of Mastodon and the Fediverse.  I certainly learned things I hadn’t known, and I’m going to
  604.    walk you through the recent drama and toss in ideas on how to improve safety.</p>
  605.    <p>For me, the story started back in early 2023 when
  606.    <a href="https://dair-community.social/@timnitGebru">Timnit Gebru</a> (the person fired by Google for questioning the
  607.    LLM-is-great orthodoxy, co-author of <cite>Stochastic Parrots</cite>) shouted loudly and eloquently that her arrival on Mastodon
  608.    was greeted by a volley of racist abuse. This shocked a lot of hyperoverprivileged people like me who don’t experience that
  609.    stuff. As the months went on after that, my perception was that the Mastodon community had pulled up its moderation socks and
  610.    things were getting better.</p>
  611.    <h2 id='p-3'>July 2024</h2>
  612.    <p>Then, just this week,
  613.    <a href="https://dair-community.social/@KimCrayton1">Kim Crayton</a> issued a passionate invitation to the “White Dudes for Kamala
  614.    Harris” event, followed immediately by examples of the racist trolling that she saw in response. With a content warning that this is
  615.    <em>not</em> pretty stuff, here are two of her posts:
  616.    <a href="https://dair-community.social/@KimCrayton1/112872020308883967">1</a>,
  617.    <a href="https://dair-community.social/@KimCrayton1/112871919476547203">2</a>.</p>
  618.    <p>Let me quote Ms Crayton:</p>
  619.    <div style="border-left: 1px solid #040;">
  620.      <blockquote><p>The racist attacks you’ve witnessed directed at me since Friday, particularly by instances with 1 or 2
  621.      individuals, SHOULD cause you to ask “why?” and here’s the part “good white folx” often miss…these attacks are about YOU…these
  622.      attacks are INTENDED to keep me from putting a mirror in your faces and showing you that YOU TOO are harmed by white supremacy
  623.      and anti-Blackness…these attacks are no different than banning books…they’re INTENDED to keep you IGNORANT about the fact that
  624.      you’re COMPLICIT</p></blockquote>
  625.    </div>
  626.    <p>She quite appropriately shouted at the community generally and the
  627.    Mastodon developers specifically. Her voice was reinforced by many others, some of whom sharpened the criticism by calling the
  628.    Mastodon team whiteness-afflicted at best and racist at worst.</p>
  629.    <p>People asked a lot of questions and we learned a few things. First of all, It turns out that some attackers came from
  630.    instances that are known to be toxic and should long-since have been defederated by Ms Crayton’s. Defederation is the
  631.    Fediverse’s nuclear weapon, our best tool for keeping even the sloppiest admins on their toes. To the extent our tools work at
  632.    all, they’re useless if they’re not applied.</p>
  633.    <p>But on the other hand it’s cheap and fast to spin up a single-user Mastodon instance that won’t get defederated until the
  634.    slime-thrower has thrown slime.</p>
  635.    <h2 id='p-2'>Invisibility</h2>
  636.    <p>What I’ve only now come to understand is that Mastodon helps griefers hide. Suppose you’re on instance A and looking at a post
  637.    from instance B, which has a comment from an account on instance C. Whether or not you can see that comment… is complicated.  But lots
  638.    of times, you can’t. Let me excerpt a couple of remarks from someone who wishes to remain anonymous.</p>
  639.    <div style="border-left: 1px solid #040;">
  640.      <blockquote><p>Thinking about how mastodon works in the context of all the poc i follow who
  641.      complain constantly about racist harassment and how often i look at their mentions and how I’ve literally never seen an
  642.      example of the abuse they’re experiencing despite actively looking for it.</p>
  643.      <p>It must be maddening to have lots of people saying horrible things to you while nobody who’d be willing to defend you can
  644.      see anyone doing anything to you.</p>
  645.      <p>But also it really does breed suspicion in allies. I believe it when people say they’re being harassed, but when I’m
  646.      looking for evidence of it on two separate instances and not ever seeing it? I have to step hard on the part of me that’s like
  647.      … really?</p></blockquote>
  648.    </div>
  649.    <h2 id='p-4'>Take-away 1</h2>
  650.    <p>This is a problem that the Masto/Fedi community can’t ignore. We can honestly say that up till now, we didn’t realize how
  651.    serious it was. Now we know.</p>
  652.    <h2 id='p-5'>Take-away 2</h2>
  653.    <p>Let’s try to cut the Mastodon developers some slack.
  654.    Here’s a quote from one, in a private chat:</p>
  655.    <div style="border-left: 1px solid #040;">
  656.      <blockquote><p>I must admit that my mentions today are making me rethink my involvement in Mastodon</p>
  657.      <p>I am burning myself out for this project for a long time, not getting much in return, and now I am a racist because
  658.      I dont fix racism.</p></blockquote>
  659.    </div>
  660.    <p>I think it is entirely reasonable to disagree with the team, which is tiny and underfunded, on their
  661.    development priorities. Especially after these last few days, it looks like a lot of people<span class='dashes'> —</span> me, for
  662.    sure<span class='dashes'> —</span> failed to dive deep into the narrated experience of
  663.    racist abuse. In the team’s defense, they’re getting yelled at <em>all the time</em> by many people, all of whom have strong
  664.    opinions about their feature that needs to ship <em>right now</em>!</p>
  665.    <h2 id='p-6'>Conversations</h2>
  666.    <p>One of the Black Fedi voices that most influences me is Mekka Okereke, who
  667.    <a href="https://hachyderm.io/@mekkaokereke/112860037633719411">weighed in intelligently</a>, from which this, on the subject
  668.    of Ms Crayton:</p>
  669.    <div style="border-left: 1px solid #040;">
  670.      <blockquote><ul>
  671. <li><p>She should not have to experience this</p></li>
  672. <li><p>It should be easier for admins at DAIR, and across the whole Fediverse, to prevent this</p></li>
  673.      </ul></blockquote>
  674.    </div>
  675.    <p>Mekka has set up a meeting with the Mastodon team and says Ms Crayton will be coming along.  I hope that turns out to be
  676.    useful. </p>
  677.    <h2 id='p-7'>More good input</h2>
  678.    <p>Let’s start with Marco Rogers, also known as
  679.    <a href="https://social.polotek.net/@polotek">@polotek@social.polotek.net</a>. I followed Marco for ages on Twitter, not always
  680.    agreeing with his strong opinions on Web/Cloud technology, but always enjoying them.  He’s been on Mastodon in recent
  681.    months and, as usual, offers
  682.    <a href="https://polotek.net/posts/a-different-vision-for-a-healthy-fediverse/">long-form opinions</a> that are worth reading.</p>
  683.    <p>He waded into the furore around our abuse problem, starting
  684.    <a href="https://social.polotek.net/@polotek/112876826937381377">here</a>, from which a few highlights.</p>
  685.    <div style="border-left: 1px solid #040;">
  686.      <blockquote><p>I see a lot of the drama that is happening between people of
  687.      color on the platform and the mastodon dev team. I feel like I need to help.</p>
  688.      <p> If people of color still find ourselves dependent on a small team of white devs to get what we want, that is a failure of
  689.      the principles of the fediverse.</p>
  690.      <p> I want to know how I can find and support people that are aligned with my values. I want to enable those people to work on a
  691.      platform that I can use. And we don't need permission from the mastodon team to do so. They're not in charge.</p></blockquote>
  692.    </div>
  693.    <p>Mekka, previously mentioned,
  694.    <a href="https://hachyderm.io/@mekkaokereke/112884976001207952">re-entered the fray</a>:</p>
  695.    <div style="border-left: 1px solid #040;">
  696.      <blockquote><p>If you run a Mastodon instance, and you don't block at least the minimum list of known terrible instances, and
  697.      you have Black users, it's just a matter of time before your users face a hate brigade.</p>
  698.      <p>That's the only reason these awful instances exist. That's all they do.</p>
  699.      <p>Telling users "Just move to a better server!" is supremely unhelpful. It doesn't help the mods, and it doesn't help the users.</p>
  700.      <p>It needs to be easier. It's currently too hard to block them and keep up with the new ones.</p></blockquote>
  701.    </div>
  702.    <p>And more;
  703.    <a href=" https://infosec.exchange/@jerry/112887084476486558">this</a> is from Jerry Bell, one of the longest-lasting Fediverse
  704.    builders (and I think the only person I’m quoting here
  705.    who doesn’t present as Black). These are short excerpts from a long and excellent piece.</p>
  706.    <div style="border-left: 1px solid #040;">
  707.      <blockquote><p>I am writing this because I'm tired of watching the cycle repeat itself, I'm tired of watching good people get
  708.      harassed, and I'm tired of the same trove of responses that inevitably follows. </p>
  709.      <p>… About this time, the sea lions show up in replies to the victim, accusing them of embracing the victim role, trying to
  710.      cause racial drama, and so on.</p>
  711.      <p>A major factor in your experience on the fediverse has to do with the instance you  sign up to.  Despite what the folks on
  712.      /r/mastodon will tell you, you won't get the same experience on every instance.</p></blockquote>
  713.      </div>
  714.    <h2 id='p-8'>What next?</h2>
  715.    <p>I don’t know. But I feel a buzz of energy, and smart people getting their teeth into the meat of the problem.</p>
  716.    <p>Now I have
  717.    thoughts to offer about moving forward.</p>
  718.    <h2 id='p-9'>Who are the enemy?</h2>
  719.    <p>They fall into two baskets: Professional and amateur. I think the current Mastodon attackers are mostly amateurs. These are
  720.    lonely Nazis, incels, channers, your basic scummy online assholes. Their organization is loose at best (“He’s pointing at
  721.    her, so I will too”), and they’re typically not well-funded nor are they deep technical experts.</p>
  722.    <p>Then there are the pros, people doing this as their day job. I suspect most of those are working for nation states, and
  723.    yes, we all know which nation states those probably are. They have sophisticated automation to help them launch armies of bots.</p>
  724.    <p>Here are some suggestions about potential fight-backs, mostly aimed at amateurs.</p>
  725.    <h2 id='p-10'>Countermeasure: Money</h2>
  726.    <p>There’s this nonprofit called
  727.    <a href="https://about.iftas.org">IFTAS</a> which is working on tools and support structures for moderation. How about they
  728.    start offering a curated allowlist of servers that it’s safe to federate with? How do you get on that list? Pay $50 to IFTAS,
  729.    which will add you to the watchlist, and also to a service scanning your members’ posts for abusive stuff during your
  730.    first month or so of operation.</p>
  731.    <p>Cue the howls of outrage saying “Many oppressed people can’t afford $50, you’re discriminating against the victims!”
  732.    I suppose, but they can still get online at any of the (many) free-to-use instances. I think it’s totally reasonable to throw a
  733.    $50 roadblock in the process of setting up a server.</p>
  734.    <p>In this world, what happens? Joe Incel sets up an instance at ownthelibs.nazi or wherever, pays his $50, and starts throwing
  735.    slime. This gets reported and pretty soon, he’s defederated. Sure, he can do it again. But how many times is this
  736.    basement-dweller willing to spend $50, leaving a paper trail each time just in case he says something that’s illegal to say in the
  737.    jurisdiction where he lives? Not that many, I think?</p>
  738.    <h2 id='p-11'>Countermeasure: Steal from Pleroma</h2>
  739.    <p>It turns out Mastodon isn’t the only Fediverse software. One of the competitors is
  740.    <a href="https://pleroma.social">Pleroma</a>. Unfortunately, it seems to be the server of choice for our attackers, because it’s
  741.    easy and cheap to set up. Having said that, its moderation facilities are generally regarded as superior to Mastodon’s, notably a
  742.    subsystem called
  743.    <a href="https://docs.pleroma.social/backend/configuration/mrf/">Message Rewrite Facility (MRF)</a> which I haven’t been near
  744.    but is frequently brought up as something that would be useful.</p>
  745.    <h2 id='p-12'>Countermeasure: Make reporting better</h2>
  746.    <p>I report abusive posts sometimes, and, as a moderator for
  747.    <a href="https://cosocial.ca">CoSocial.ca</a> I see reports too.  I think the “Report post” interface on many clients is weak,
  748.    asking you unnecessary questions.</p>
  749.    <p>And when I get a report, it seems like half the time none of the abusive material is attached, and it takes me multiple
  750.    clicks to look at the reported account’s feed, which feels like a pretty essential step.</p>
  751.    <p>Here’s how I’d like reporting to work.</p>
  752.    <ol>
  753.      <li><p>There’s a single button labeled “Report this post”. When you click it, a popup says “Reported, thanks” and you’re
  754.      done.  Maybe it could query whether you want to block the user or instance, but it’s super important that the process be
  755.      lightweight.</p></li>
  756.      <li><p>The software should pull together a report package including the reported post’s text and graphics. (Not just the URLs,
  757.      because the attackers like to cover their tracks.) Also the attacker’s profile page. No report should ever be filed without
  758.      evidence.</p></li>
  759.    </ol>
  760.    <h2 id='p-14'>Countermeasure: Rules of thumb</h2>
  761.    <p>Lauren offered this: Suppose a reply or mention comes in for someone on Instance A from someone on Instance B. Suppose
  762.    Instance A could check whether anyone else on A follows anyone on B. If not, reject the incoming message. This would have to be
  763.    a per-user not global setting, and I see it as a placeholder for a whole class of heuristics that could usefully get in the
  764.    attackers’ way.</p>
  765.    <h2 id='p-13'>Wish us luck</h2>
  766.    <p>Obviously I’m not claiming that any of these ideas are the magic bullet that’s going to slay the online-abuse monster. But we
  767.    do need ideas to work with, because it’s not a monster that we can afford to ignore.</p>
  768.    <p>I care intensely about this, because I think decentralization is an essential ingredient of online conversation, and online
  769.    conversation is valuable, and if we can’t make it safe we won’t have it.</p>
  770. </div></content></entry>
  771.  
  772. <entry>
  773. <title>Union of Finite Automata</title>
  774. <link href='https://www.tbray.org/ongoing/When/202x/2024/07/28/Union-of-Finite-Automata' />
  775. <link rel='replies'        thr:count='0'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/07/28/Union-of-Finite-Automata#comments' />
  776. <id>https://www.tbray.org/ongoing/When/202x/2024/07/28/Union-of-Finite-Automata</id>
  777. <published>2024-07-28T12:00:00-07:00</published>
  778. <updated>2024-07-29T13:38:55-07:00</updated>
  779. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Quamina Diary' />
  780. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  781. <category scheme='https://www.tbray.org/ongoing/What/' term='Quamina Diary' />
  782. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>In building Quamina, I needed to compute the union of two finite automata (FAs). I remembered from some university course 100 years     ago that this was possible in theory, so I went looking for the algorithm, but was left unhappy.     The descriptions I found tended to be hyper-academic, loaded with mathematical notation that I found unhelpful, and     didn’t describe an approach that I thought a reasonable programmer would reasonably take. The purpose of this <span class="o">ongoing</span> entry is to present a      programmer-friendly description of the problem and of the algorithm I adopted, with the hope that some future developer, facing     the same problem, will have a more satisfying search experience</div></summary>
  783. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  784.    <p>In building Quamina, I needed to compute the union of two finite automata (FAs). I remembered from some university course 100 years
  785.    ago that this was possible in theory, so I went looking for the algorithm, but was left unhappy.
  786.    The descriptions I found tended to be hyper-academic, loaded with mathematical notation that I found unhelpful, and
  787.    didn’t describe an approach that I thought a reasonable programmer would reasonably take. The purpose of this <span
  788.    class='o'>ongoing</span> entry is to present a
  789.    programmer-friendly description of the problem and of the algorithm I adopted, with the hope that some future developer, facing
  790.    the same problem, will have a more satisfying search experience.</p>
  791.    <p>There is very little math in this discussion (a few subscripts), and no
  792.    circles-and-arrows pictures. But it does have working Go code.</p>
  793.    <h2 id='p-1'>Finite automata?</h2>
  794.    <p>I’m not going to rehash the theory of FAs (often called state machines). In practice the purpose of an FA is to match (or
  795.    fail to match) some
  796.    input against some pattern. What the software does when the input matches the pattern (or doesn’t) isn’t relevant to
  797.    our discussion today.
  798.    Usually the inputs are strings and the patterns are regular expressions or equivalent. In practice, you compile a pattern
  799.    into an FA, and then you go through the input, character by character, trying to traverse the FA to find out whether it matches
  800.    the input.</p>
  801.    <p>An FA has a bunch of states, and for each state
  802.    there can be a list of input symbols that lead to transitions to other states. What exactly I mean by “input symbol” turns out to be
  803.    interesting and affects your choice of algorithm, but let’s ignore that for now.</p>
  804.    <p>The following statements apply:</p>
  805.    <ol>
  806.      <li><p>One state is designated as the “start state” because, well, that’s where you start.</p></li>
  807.      <li><p>Some states are called “final”, and reaching them means you’ve matched one or more patterns. In Quamina’s FAs, each
  808.      state has an extra field (usually empty) saying “if you got here you matched P*, yay!”, where P* is a list of labels for the
  809.      (possibly more than one) patterns you matched.</p></li>
  810.      <li><p>It is possible that you’re in a state and for some particular input, you transition to more than one other state. If
  811.      this is true, your FA is <em>nondeterministic</em>, abbreviated NFA.</p></li>
  812.      <li><p>It is possible that a state can have one or more “epsilon transitions”, ones that you can just take any time, not requiring
  813.      any particular input. (I wrote about this in
  814.      <a href="/ongoing/When/202x/2024/06/17/Epsilon-Love">Epsilon Love</a>.)
  815.      Once again, if this is true, you’ve got an NFA. If neither this statement nor the previous are true, it’s
  816.      a <em>deterministic</em> finite automaton, DFA.</p></li>
  817.    </ol>
  818.    <p>The discussion here works for NFAs, but lots of interesting problems can be solved with DFAs, which are simpler and faster,
  819.    and this algorithm works there too.</p>
  820.    <h2 id='p-2'>Union?</h2>
  821.    <p>If I have <code>FA1</code> that matches “foo” and <code>FA2</code> that matches “bar”, then their union,
  822.    <code>FA1 ∪ FA2</code>, matches both “foo”
  823.    and “bar”. In practice Quamina often computes the union of a large number of FAs, but it does so a pair at a time, so we’re
  824.    only going to worry about the union of two FAs.</p>
  825.    <h2 id='p-3'>The academic approach</h2>
  826.    <p>There are plenty of Web pages and YouTubes covering this. Most of them are full of Greek characters and math symbols. They go
  827.    like this:</p>
  828.    <ol>
  829.      <li><p>You have two FAs, call them <code>A</code> and <code>B</code>. <code>A</code> has states <code>A<sub>1</sub></code>, …
  830.      <code>A<sub>maxA</sub></code>, <code>B</code> has <code>B<sub>1</sub></code>, … <code>B<sub>maxB</sub></code></p></li>
  831.      <li><p>The union contains all the states in <code>A</code>, all the states in <code>B</code>, and the “product” of
  832.      <code>A</code> and <code>B</code>, which is to say states you could call <code>A<sub>1</sub>B<sub>1</sub></code>,
  833.      <code>A<sub>1</sub>B<sub>2</sub></code>, <code>A<sub>2</sub>B<sub>1</sub></code>, <code>A<sub>2</sub>B<sub>2</sub></code>,
  834.      … <code>A<sub>maxA</sub>B<sub>maxB</sub></code>.</p></li>
  835.      <li><p>For each state <code>A<sub>X</sub>B<sub>Y</sub></code>, you work out its transitions by looking at the transitions of
  836.      the two states being combined. For some input symbol, if <code>A<sub>X</sub></code> has a transition to
  837.      <code>A<sub>XX</sub></code> but <code>B<sub>Y</sub></code> has no transition, then the combined state just has the A
  838.      transition. The reverse for an input where <code>B<sub>Y</sub></code> has a transition but <code>A<sub>X</sub></code>
  839.      doesn’t. And if <code>A<sub>X</sub></code> transitions to <code>A<sub>XX</sub></code> and <code>B<sub>Y</sub></code> transitions to
  840.      <code>B<sub>YY</sub></code>, then the transition is to <code>A<sub>XX</sub>B<sub>YY</sub></code>.</p></li>
  841.      <li><p>Now you’ll have a lot of states, and it usually turns out that many of them aren’t reachable. But there are plenty of
  842.      algorithms to filter those out. You’re done, you’ve computed the union and <code>A<sub>1</sub>B<sub>1</sub></code> is its
  843.      start state!</p></li>
  844.    </ol>
  845.    <h2 id='p-4'>Programmer-think</h2>
  846.    <p>If you’re like me, the idea of computing all the states, then throwing out the unreachable ones, feels wrong. So here’s
  847.    what I suggest, and has worked well in practice for Quamina:</p>
  848.    <ol>
  849.      <li><p>First, merge <code>A<sub>1</sub></code> and <code>B<sub>1</sub></code> to make your new start state
  850.      <code>A<sub>1</sub>B<sub>1</sub></code>. Here’s how:</p></li>
  851.      <li><p>If an input symbol causes no transitions in either <code>A<sub>1</sub></code> or <code>B<sub>1</sub></code>, it also
  852.      doesn’t cause any in <code>A<sub>1</sub>B<sub>1</sub></code>.</p></li>
  853.      <li><p>If an input symbol causes a transition in <code>A<sub>1</sub></code> to <code>A<sub>X</sub></code> but no transition
  854.      in <code>B<sub>1</sub></code>, then you adopt <code>A<sub>X</sub></code> into the union, and any other <code>A</code> states
  855.      it points to, and any they point to, and so on.</p></li>
  856.      <li><p>And of course if <code>B<sub>1</sub></code> has a transition to <code>B<sub>Y</sub></code> but
  857.      <code>A<sub>1</sub></code> doesn’t transition, you flip it the other way, adopting <code>B<sub>Y</sub></code> and its
  858.      descendents.</p></li>
  859.      <li><p>And if <code>A<sub>1</sub></code> transitions to <code>A<sub>X</sub></code> and <code>B<sub>1</sub></code> transitions
  860.      to <code>B<sub>Y</sub></code>, then you adopt a new state <code>A<sub>X</sub>B<sub>Y</sub></code>, which you compute
  861.      recursively the way you just did for <code>A<sub>1</sub>B<sub>1</sub></code>. So you’ll never compute anything that’s not
  862.      reachable.</p></li>
  863.    </ol>
  864.    <p>I could stop there. I think that’s enough for a competent developers to get the idea?  But it turns out there
  865.    are a few details, some of them interesting. So, let’s dig in.</p>
  866.    <h2 id='p-5'>“Input symbol”?</h2>
  867.    <p>The academic discussion of FAs is very abstract on this subject, which is fair enough, because when you’re talking about how
  868.    to build, or traverse, or compute the union of FAs, the algorithm doesn’t depend very much on what the symbols actually are. But
  869.    when you’re writing code, it turns out to matter a lot.</p>
  870.    <p>In practice, I’ve done a lot of work with FAs over the years, and I’ve only ever seen four things used as input symbols
  871.    to drive them. They are:</p>
  872.    <ul>
  873.      <li><p>Unicode “characters” represented by code points, integers in the range 0…1,114,111 inclusive.</p></li>
  874.      <li><p>UTF-8 bytes, which have values in the range 0…244 inclusive.</p></li>
  875.      <li><p>UTF-16 values, unsigned 16-bit integers. I’ve only ever seen this used in Java programs because that’s what
  876.      its native <code>char</code> type is. You probably don’t want to do this.</p></li>
  877.      <li><p>Enum values, small integers with names, which tend to come in small collections.</p></li>
  878.    </ul>
  879.    <p>As I said, this is all I’ve seen, but 100% of the FAs that I’ve seen automatically generated and subject to
  880.    set-arithmetic operations like Union are based on UTF-8. And that’s what Quamina uses, so that’s what I’m going to use in the
  881.    rest of this discussion.</p>
  882.    <h2 id='p-7'>Code starts here</h2>
  883.    <p>This comes from Quamina’s
  884.    <a href="https://github.com/timbray/quamina/blob/main/nfa.go">nfa.go</a>. We’re going to look at the function
  885.    <code>mergeFAStates</code>, which implements the merge-two-states logic described above.</p>
  886.    <p>Lesson: This process can lead to a lot of wasteful work. Particularly if either or both of the states transition on ranges of
  887.    values like <code>0…9</code> or <code>a…z</code>. So we only want to do the work merging any pair of states once, and we want
  888.    there only to be one merged value.  Thus we start with a straightforward memo-ization.</p>
  889.    <div class="tbc"><pre>
  890. <span class="kd">func</span><span class="w"> </span><span class="nx">mergeFAStates</span><span class="p">(</span><span class="nx">state1</span><span class="p">,</span><span class="w"> </span><span class="nx">state2</span><span class="w"> </span><span class="o">*</span><span class="nx">faState</span><span class="p">,</span><span class="w"> </span><span class="nx">keyMemo</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="nx">faStepKey</span><span class="p">]</span><span class="o">*</span><span class="nx">faState</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="nx">faState</span><span class="w"> </span><span class="p">{</span>
  891. <span class="w">    </span><span class="c1">// try to memo-ize</span>
  892. <span class="w">    </span><span class="nx">mKey</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">faStepKey</span><span class="p">{</span><span class="nx">state1</span><span class="p">,</span><span class="w"> </span><span class="nx">state2</span><span class="p">}</span>
  893. <span class="w">    </span><span class="nx">combined</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">keyMemo</span><span class="p">[</span><span class="nx">mKey</span><span class="p">]</span>
  894. <span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="p">{</span>
  895. <span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">combined</span>
  896. <span class="w">    </span><span class="p">}</span>
  897. </pre>
  898.    <p>Now some housekeeping. Remember, I noted above that any state might contain a signal saying that arriving here
  899.    means you’ve matched pattern(s). This is called <code>fieldTransitions</code>, and the merged state obviously has to
  900.    match all the things that either of the merged states match. Of course, in the vast majority of cases neither merged state
  901.    matched anything and so this is a no-op.</p>
  902. <pre>
  903. <span class="w">    </span><span class="nx">fieldTransitions</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">state1</span><span class="p">.</span><span class="nx">fieldTransitions</span><span class="p">,</span><span class="w"> </span><span class="nx">state2</span><span class="p">.</span><span class="nx">fieldTransitions</span><span class="o">...</span><span class="p">)</span></pre>
  904.    <p>Since our memo-ization attempt came up empty, we have to allocate an empty structure for the new merged state, and add it to the
  905.    memo-izer.</p>
  906.    <pre>
  907. <span class="w">    </span><span class="nx">combined</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">faState</span><span class="p">{</span><span class="nx">table</span><span class="p">:</span><span class="w"> </span><span class="nx">newSmallTable</span><span class="p">(),</span><span class="w"> </span><span class="nx">fieldTransitions</span><span class="p">:</span><span class="w"> </span><span class="nx">fieldTransitions</span><span class="p">}</span>
  908. <span class="w">    </span><span class="nx">keyMemo</span><span class="p">[</span><span class="nx">mKey</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">combined</span></pre>
  909.    <p>Here’s where it gets interesting.  The algorithm talks about looking at the inputs that cause transitions in the states we’re
  910.    merging. How do you find them?  Well, in the case where you’re transitioning on UTF-8 bytes, since there are only 244 values,
  911.    why not do the simplest thing that could possibly work and just check each byte value?</p>
  912.    <p>Every Quamina state contains a table that encodes the byte transitions, which operates  like the Go construct
  913.    <code>map[byte]state</code>. Those tables are implemented in
  914.    <a href="/ongoing/When/202x/2022/06/25/Small-Tables">a compact data structure optimized for fast traversal</a>. But for doing this
  915.    kind of work, it’s easy to “unpack” them into a fixed-sized table; in Go, <code>[244]state</code>. Let’s do that for the states
  916.    we’re merging and for the new table we’re building.</p>
  917. <pre><span class="w">    </span><span class="nx">u1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">unpackTable</span><span class="p">(</span><span class="nx">state1</span><span class="p">.</span><span class="nx">table</span><span class="p">)</span>
  918. <span class="w">    </span><span class="nx">u2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">unpackTable</span><span class="p">(</span><span class="nx">state2</span><span class="p">.</span><span class="nx">table</span><span class="p">)</span>
  919. <span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">uComb</span><span class="w"> </span><span class="nx">unpackedTable</span></pre>
  920. <p><code>uComb</code> is where we’ll fill in the merged transitions.</p>
  921. <p>Now we’ll run through all the possible input values; <code>i</code> is the byte value,  <code>next1</code> and <code>next2</code>
  922. are the transitions on that value. In practice, <code>next1</code> and <code>next2</code> are going to be null most of the time.</p>
  923. <pre><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">next1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">u1</span><span class="w"> </span><span class="p">{</span>
  924. <span class="w">        </span><span class="nx">next2</span><span class="w"> </span><span class="o">:=</span><span class="w"></span><span class="nx"> u2</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span></pre>
  925.    <p>Here’s where we start building up the new transitions in the unpacked array <code>uComb</code>.</p>
  926.    <p>For many values of <code>i</code>, you can avoid actually merging the states to create a new one. If the transition is the
  927.    same in both input FAs, or if either of them are null, or if the transitions for this value of <code>i</code> are the same as
  928.    for the last value.  This is all about avoiding unnecessary work and the <code>switch</code>/<code>case</code> structure is the
  929.    result of a bunch of profiling and optimization.</p>
  930. <pre><span class="w">        </span><span class="k">switch</span><span class="w"> </span><span class="p">{</span>
  931. <span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="nx">next1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">next2</span><span class="p">:</span><span class="w"> </span><span class="c1">// no need to merge</span>
  932. <span class="w">            </span><span class="nx">uComb</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">next1</span>
  933. <span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="nx">next2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">nil</span><span class="p">:</span><span class="w"> </span><span class="c1">// u1 must be non-nil</span>
  934. <span class="w">            </span><span class="nx">uComb</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">next1</span>
  935. <span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="nx">next1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">nil</span><span class="p">:</span><span class="w"> </span><span class="c1">// u2 must be non-nil</span>
  936. <span class="w">            </span><span class="nx">uComb</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">next2</span>
  937. <span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">next1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">u1</span><span class="p">[</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">next2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">u2</span><span class="p">[</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span><span class="w"> </span><span class="c1">// dupe of previous step - happens a lot</span>
  938. <span class="w">            </span><span class="nx">uComb</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">uComb</span><span class="p">[</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span></pre>
  939.    <p>If none of these work, we haven’t been able to avoid merging the two states. We do that by a recursive call to invoke
  940.    all the logic we just discussed.</p>
  941.    <p>There is a complication. The automaton might be nondeterministic, which means that there might be more than one transition
  942.    for some byte value. So the data structure actually behaves like <code>map[byte]*faNext</code>, where <code>faNext</code> is a
  943.    wrapper for a list of states you can transition to.</p>
  944.    <p>So here we’ve got a nested loop to recurse for each possible combination of transitioned-to states that can occur on this
  945.    byte value. In a high proportion of cases the FA is deterministic, so there’s only one state from each FA being merged and this
  946.    nested loop collapses to a single recursive call.</p>
  947. <pre><span class="w">        </span><span class="k">default</span><span class="p">:</span><span class="w"> </span><span class="c1">// have to recurse &amp; merge</span>
  948. <span class="w">            </span><span class="kd">var</span><span class="w"> </span><span class="nx">comboNext</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">faState</span>
  949. <span class="w">            </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">nextStep1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">next1</span><span class="p">.</span><span class="nx">states</span><span class="w"> </span><span class="p">{</span>
  950. <span class="w">                </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">nextStep2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">next2</span><span class="p">.</span><span class="nx">states</span><span class="w"> </span><span class="p">{</span>
  951. <span class="w">                    </span><span class="nx">comboNext</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">comboNext</span><span class="p">,</span><span class="w"> </span><span class="nx">mergeFAStates</span><span class="p">(</span><span class="nx">nextStep1</span><span class="p">,</span><span class="w"> </span><span class="nx">nextStep2</span><span class="p">,</span><span class="w"> </span><span class="nx">keyMemo</span><span class="p">))</span>
  952. <span class="w">                </span><span class="p">}</span>
  953. <span class="w">            </span><span class="p">}</span>
  954. <span class="w">            </span><span class="nx">uComb</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">faNext</span><span class="p">{</span><span class="nx">states</span><span class="p">:</span><span class="w"> </span><span class="nx">comboNext</span><span class="p">}</span>
  955. <span class="w">        </span><span class="p">}</span>
  956. <span class="w">    </span><span class="p">}</span></pre>
  957.    <p>We’ve filled up the unpacked state-transition table, so we’re almost done. First, we have to compress it into its
  958.    optimized-for-traversal form.</p>
  959. <pre><span class="w">    </span><span class="nx">combined</span><span class="p">.</span><span class="nx">table</span><span class="p">.</span><span class="nx">pack</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">uComb</span><span class="p">)</span></pre>
  960.    <p>Remember, if the FA is nondeterministic, each state can have “epsilon” transitions which you can follow any time without
  961.    requiring any particular input. The merged state needs to contain all the epsilon transitions from each input state.</p>
  962. <pre><span class="w">    </span><span class="nx">combined</span><span class="p">.</span><span class="nx">table</span><span class="p">.</span><span class="nx">epsilon</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">state1</span><span class="p">.</span><span class="nx">table</span><span class="p">.</span><span class="nx">epsilon</span><span class="p">,</span><span class="w"> </span><span class="nx">state2</span><span class="p">.</span><span class="nx">table</span><span class="p">.</span><span class="nx">epsilon</span><span class="o">...</span><span class="p">)</span>
  963.  
  964. <span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">combined</span>
  965. <span class="p">}</span></pre>
  966.    </div>
  967.    <p>And, we’re done. I mean, we are once all those recursive calls have finished crawling through the states being merged.</p>
  968.    <h2 id='p-8'>Is that efficient?</h2>
  969.    <p>As I said above, this is an example of a “simplest thing that could possibly work” design. Both the recursion and the
  970.    unpack/pack sequence are kind of code smells, suggesting that this could be a pool of performance quicksand.</p>
  971.    <p>But apparently not. I ran a benchmark where I added 4,000 patterns synthesized from the Wordle
  972.    word-list; each of them looked like this:</p>
  973.    <p><code>{"allis": { "biggy": [ "ceils", "daisy", "elpee", "fumet", "junta", … </code> (195 more).</p>
  974.    <p>This produced a <em>huge</em> deterministic FA with about 4.4 million states, with the addition of these hideous worst-case
  975.    patterns running at 500/second. Good enough for rock ’n’ roll.</p>
  976.    <p>How about nondeterministic FAs? I went back to that Wordle source and, for each of its 12,959 words, added a pattern with a
  977.    random wildcard; here are three of them:</p>
  978.    <p><code>{"x": [ {"shellstyle": "f*ouls" } ] }<br/>
  979. {"x": [ {"shellstyle": "pa*sta" } ] }<br/>
  980. {"x": [ {"shellstyle": "utter*" } ] }</code></p>
  981.   <p>This produced an NFA with 46K states, the addition process ran at 70K patterns/second.
  982.   </p>
  983.   <p>Sometimes the simplest thing that could possibly work, works.</p>
  984. </div></content></entry>
  985.  
  986. <entry>
  987. <title>Terse Directions</title>
  988. <link href='https://www.tbray.org/ongoing/When/202x/2024/07/19/Short-Directions' />
  989. <link rel='replies'        thr:count='9'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/07/19/Short-Directions#comments' />
  990. <id>https://www.tbray.org/ongoing/When/202x/2024/07/19/Short-Directions</id>
  991. <published>2024-07-19T12:00:00-07:00</published>
  992. <updated>2024-07-19T15:40:22-07:00</updated>
  993. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Software' />
  994. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  995. <category scheme='https://www.tbray.org/ongoing/What/' term='Software' />
  996. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>This post describes a service I want from my online-map provider.     I’d use it all the time. Summary: When I’m navigating an area I already know about, don’t give me turn-by-turn, just     give me a short list of the streets to take</div></summary>
  997. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  998.    <p>This post describes a service I want from my online-map provider.
  999.    I’d use it all the time. Summary: When I’m navigating an area I already know about, don’t give me turn-by-turn, just
  1000.    give me a short list of the streets to take.</p>
  1001.    <p>I’ve been living in Vancouver for decades and, driving or cycling, know how to get almost anywhere.  It helps that, like most
  1002.    North American cities, we have a fairly regular north-south-east-west grid.
  1003.    These days, when I’m going any distance by car, I get directions from Google Maps because it knows where the traffic is bad, and
  1004.    the traffic is usually bad somewhere.  But it gives me way more directions than I need. Let’s look at a concrete example.</p>
  1005.    <img src="https://www.tbray.org/ongoing/When/202x/2024/07/19/vancouver-streets.png" alt="Part of central and east Vancouver" />
  1006.    <div class='caption'><p>To follow the narrative, you’ll probably have to click to expand, and it’s pretty big. It may be easier
  1007.    just to open
  1008.    <a href="https://www.openstreetmap.org/#map=14/49.2698/-123.0918">the map</a> in another window.<br/>Map credit:
  1009.    OpenStreetMap.</p></div>
  1010.    <p>My place is near the bottom edge of this map off to the west, between Cambie and Main streets. I occasionally attend a meetup
  1011.    at New Brighton Park, which is the little splodge of green at the very top right corner of the map, across the highway
  1012.    from Hastings Racecourse. It’s on McGill street.
  1013.    To get there, I have to go quite a distance both east and north. Candidates for north/south travel include
  1014.    Main, Clark, Nanaimo, and Renfrew streets. Candidates for east/west include 12th, Broadway, 1st, and Hastings.</p>
  1015.    <p>Right now, Google Maps insists on turn-by turn, with three warnings for each turn. It’s dumb and annoying and interrupts
  1016.    whatever music or show I’m listening to.</p>
  1017.    <p>What I want is to get in the car and say “Short directions to New Brighton Park” and have it say “Take Main to 12th to Nanaimo to
  1018.    1st to Renfrew to McGill.” Then when I’m driving, I’d get one vocal warning a block out from each turn,
  1019.    like “Next left on Nanaimo” or some such.</p>
  1020.    <p>Of course, when I’m navigating in a strange place, I’d want the traditional turn-by-turn. Don’t know about you, but the bulk
  1021.    of my navigation is in territory I know and mostly about avoiding traffic.</p>
  1022.    <p>The OpenStreetMap data is public and good. Traffic data is… a problem. But for anyone who has it, you can have me for a
  1023.    customer. Just learn to be terse.</p>
  1024. </div></content></entry>
  1025.  
  1026. <entry>
  1027. <title>2009 Ranger</title>
  1028. <link href='https://www.tbray.org/ongoing/When/202x/2024/07/12/2009-Ranger' />
  1029. <link rel='replies'        thr:count='8'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/07/12/2009-Ranger#comments' />
  1030. <id>https://www.tbray.org/ongoing/When/202x/2024/07/12/2009-Ranger</id>
  1031. <published>2024-07-12T12:00:00-07:00</published>
  1032. <updated>2024-07-17T10:43:44-07:00</updated>
  1033. <category scheme='https://www.tbray.org/ongoing/What/' term='The World/Products/Automobiles' />
  1034. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  1035. <category scheme='https://www.tbray.org/ongoing/What/' term='Products' />
  1036. <category scheme='https://www.tbray.org/ongoing/What/' term='Automobiles' />
  1037. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>This week we’re vacationing at the family cabin on     <a href='https://en.wikipedia.org/wiki/Keats_Island_(British_Columbia)'>an island</a>;     the nearest town is     <a href='https://en.wikipedia.org/wiki/Gibsons'>Gibsons</a>.     Mid-week, we hit     town to pick up groceries and hardware. Unfortunately, it’s a really demanding walk from the waterfront to the     mall, particularly with a load to carry, and there’s little public transit. Fortunately, there’s     <a href='https://www.coastcarco-op.ca'>Coast Car Co-op</a>, a competent and friendly little five-car outfit. We booked a couple     of hours and the closest vehicle was a 2009     <a href='https://en.wikipedia.org/wiki/Ford_Ranger'>Ford Ranger</a>, described as a “compact pickup” or “minitruck”. It made     me think</div></summary>
  1038. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1039.    <p>This week we’re vacationing at the family cabin on
  1040.    <a href="https://en.wikipedia.org/wiki/Keats_Island_(British_Columbia)">an island</a>;
  1041.    the nearest town is
  1042.    <a href="https://en.wikipedia.org/wiki/Gibsons">Gibsons</a>.
  1043.    Mid-week, we hit
  1044.    town to pick up groceries and hardware. Unfortunately, it’s a really demanding walk from the waterfront to the
  1045.    mall, particularly with a load to carry, and there’s little public transit. Fortunately, there’s
  1046.    <a href="https://www.coastcarco-op.ca">Coast Car Co-op</a>, a competent and friendly little five-car outfit. We booked a couple
  1047.    of hours and the closest vehicle was a 2009
  1048.    <a href="https://en.wikipedia.org/wiki/Ford_Ranger">Ford Ranger</a>, described as a “compact pickup” or “minitruck”. It made
  1049.    me think.</p>
  1050.    <img src="https://www.tbray.org/ongoing/When/202x/2024/07/12/white-ranger.png" alt="2009 Ford Ranger" />
  1051.    <h2 id='p-1'>Think back fifteen years</h2>
  1052.    <p>I got in the Ranger and tried to adjust the seat, but that was as far back as it went. It didn’t go up or down. There were no
  1053.    cameras to help me back up. There was nowhere to plug my phone in.  It had a gearshift on the steering column that moved a little red
  1054.    needle in a PRNDL tucked under the speedometer. There was no storage except for the truck bed. It wasn’t very fast. The radio
  1055.    was just a radio. It was smaller than almost anything on the road. I had to manipulate a a physical “key” thing to make it go.
  1056.    To open and close the window, you have to turn a crank.
  1057.    I bet there were hardly any CPUs under the hood.</p>
  1058.    <p>And, it was… perfectly OK.</p>
  1059.    <p>The rear-view mirrors were big and showed me what I needed. It was dead easy to park, I could see
  1060.    all four of its corners. There was enough space in the back to carry all our stuff with plenty room to spare. You wouldn’t want
  1061.    to drive fast in a small tourist town with lots of steep hills, blind corners, and distracted pedestrians.
  1062.    It wasn’t tracking my trips and selling the info. The seats were comfy enough.</p>
  1063.    <h2 id='p-2'>Car companies: Dare to do less</h2>
  1064.    <p>I couldn’t possibly walk away from our time in the Ranger without thinking about the absolutely insane amounts of money
  1065.    and resources and carbon loading we could save by building smaller, simpler, cheaper, dumber, automobiles.</p>
  1066. </div></content></entry>
  1067.  
  1068. <entry>
  1069. <title>Q Numbers</title>
  1070. <link href='https://www.tbray.org/ongoing/When/202x/2024/07/09/Q-Numbers' />
  1071. <link rel='replies'        thr:count='4'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/07/09/Q-Numbers#comments' />
  1072. <id>https://www.tbray.org/ongoing/When/202x/2024/07/09/Q-Numbers</id>
  1073. <published>2024-07-09T12:00:00-07:00</published>
  1074. <updated>2024-07-09T12:00:00-07:00</updated>
  1075. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Quamina Diary' />
  1076. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  1077. <category scheme='https://www.tbray.org/ongoing/What/' term='Quamina Diary' />
  1078. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>This <span class="o">ongoing</span> fragment describes how to match and compare numbers using a finite automaton, which involves     transforming them into strings with the right lexical properties. My hope is that there are at least twelve people in the world who     are interested in the intersection of numeric representation and finite automata.<br/> <i>[Note: This whole piece, except for the description of the problem, has been obsoleted by     <a href='/ongoing/When/202x/2024/08/28/Q-Numbers-2'>Q Numbers Redux</a>.]</i></div></summary>
  1079. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1080.    <p>This <span class='o'>ongoing</span> fragment describes how to match and compare numbers using a finite automaton, which involves
  1081.    transforming them into strings with the right lexical properties. My hope is that there are at least twelve people in the world who
  1082.    are interested in the intersection of numeric representation and finite automata.<br/>
  1083.    <i>[Note: This whole piece, except for the description of the problem, has been obsoleted by
  1084.    <a href="/ongoing/When/202x/2024/08/28/Q-Numbers-2">Q Numbers Redux</a>.]</i></p>
  1085.    <h2 id='p-2'>Background</h2>
  1086.    <p>(Feel free to skip this part if you already know about Quamina.)</p>
  1087.    <p>This is yet another entry in the
  1088.    <a href="/ongoing/What/Technology/Quamina%20Diary/">Quamina Diary</a> series of blog posts. Quamina is a Go-language library
  1089.    that allows you to compile a bunch of “Patterns” together and, when presented with “events”, i.e. JSON data blobs, informs you
  1090.    which (if any) of the Patterns match each event, at a speed which is high (often millions/second) and only weakly related to the
  1091.    number of Patterns in any Quamina instance.</p>
  1092.    <p>Quamina was inspired by
  1093.    <a href="https://github.com/aws/event-ruler">AWS Event Ruler</a> (“Ruler” for short), a package I helped develop while at AWS
  1094.    that has since been open-sourced. (Thanks, AWS!) By “based on” I mean “does a subset of the same things compatibly, with a design that
  1095.    is quite different, in interesting ways”. Quamina is also a fruitful source of software geekery for me to write about
  1096.    here, which I enjoy.</p>
  1097.    <h2 id='p-1'>The problem</h2>
  1098.    <p>Suppose you want to match records for boxes whose height is 20cm. A sample of such a record, with most fields
  1099.    removed:</p>
  1100.    <pre><code>{
  1101.  "box": {
  1102.    "dimensions": {
  1103.      "width": 100,
  1104.      "height": 20,</code></pre>
  1105.    <p>(Much omitted.)</p>
  1106.    <p>A Quamina Pattern designed to match those records would look like this:</p>
  1107.    <pre><code>{
  1108.  "box": {
  1109.    "dimensions": {
  1110.      "height": [ 20 ]
  1111.    }
  1112.  }
  1113. }</code></pre>
  1114.    <p>All good so far.  But what if, due to some upstream computer program or inventory admin, a
  1115.    message showed up like so?</p>
  1116.    <pre><code>{
  1117.  "box": {
  1118.    "dimensions": {
  1119.      "width": 100.0,
  1120.      "height": 20.0,
  1121. </code></pre>    
  1122.    <p>Up until my last PR landed, Quamina didn’t know that “20” and “20.0” and “2.0e1” were the same quantity; it knew how to
  1123.    compare strings to other strings and that was all. Which was unsatisfactory. And a problem which had been solved years ago
  1124.    (partly by me) in Ruler.</p>
  1125.    <h2 id='p-10'>Question</h2>
  1126.    <p>Pause a moment and ask yourself: How would you write a finite automaton which would Do The Right Thing with numbers?
  1127.    I’m not going to claim that the way Ruler and Quamina do it is optimal, but it’s worked pretty well for years and processed
  1128.    trillions of events with no breakages I know of.</p>
  1129.    <p>Our answer: normalize the numbers into fixed-sized strings whose lexical ordering is that of the numbers they represent.
  1130.    Code first:</p>
  1131.    <div class="tbc"><pre>
  1132. <span class="kd">func</span><span class="w"> </span><span class="nx">qNumFromFloat</span><span class="p">(</span><span class="nx">f</span><span class="w"> </span><span class="kt">float64</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">qNumber</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
  1133. <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">f</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="o">-</span><span class="nx">FiveBillion</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nx">f</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="nx">FiveBillion</span><span class="w"> </span><span class="p">{</span>
  1134. <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">&quot;value must be between -5e9 and +5e9 inclusive&quot;</span><span class="p">)</span>
  1135. <span class="w"> </span><span class="p">}</span>
  1136. <span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">uint64</span><span class="p">(</span><span class="nx">TenE6</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="nx">FiveBillion</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">f</span><span class="p">))</span>
  1137. <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">toHexStringSkippingFirstByte</span><span class="p">(</span><span class="nx">value</span><span class="p">),</span><span class="w"> </span><span class="kc">nil</span>
  1138. <span class="p">}</span>
  1139.    </pre></div>
  1140.    <h2 id='p-3'>Constraints</h2>
  1141.    <p>Quamina requires, for numeric matching to work properly, that:</p>
  1142.    <ol>
  1143.      <li><p>The numbers be between -/+5×10<sup>9</sup>, inclusive.</p></li>
  1144.      <li><p>The numbers have no more than five digits to the right of the decimal point.</p></li>
  1145.    </ol>
  1146.    <p>You’ll notice that the code above enforces the first condition but not the second. We’ll get to that.</p>
  1147.    <h2 id='p-4'>Effects</h2>
  1148.    <p>So, what that code is doing is:</p>
  1149.    <ol>
  1150.      <li><p>Adding 5.0e9 to the number so it’s in the range 0 … 10.0e9.</p></li>
  1151.      <li><p>Multiplying by 10<sup>6</sup> to push the five-digit fractional part to the left of the decimal point, preserving its
  1152.      sixth digit (if any) so the rounding in the next step works.</p></li>
  1153.      <li><p>Converting it from a <code>float64</code> into a <code>uint64</code>.</p></li>
  1154.      <li><p>Turning that into a big-endian 14-byte hex string.</p></li>
  1155.    </ol>
  1156.    <p>So any number that meets the constraints above is represented as 14 hex digits whose lexical order is consistent with the
  1157.    underlying numbers. “20”, “20.0” and “2.0e1” are all “11C3793911AD00”. Which means that this Pattern will do what reasonable
  1158.    people expect:
  1159.    <pre><code>{"box": { "dimensions": { "height": [ 20 ] } } }</code></pre></p>
  1160.    <h2 id='p-5'>More formally</h2>
  1161.    <p>There are 10<sup>15</sup> numbers that meet the constraints described above. This process maps them into hex strings. The
  1162.    first three and their mappings are:<br/>
  1163.    <pre><code>-5,000,000,000, -4,999,999,999.99999, -4,999,999,999.99998</code>
  1164. <code>00000000000000,       00000000000009,       00000000000014</code></pre></p>
  1165.    <p>And the last three:<br/>
  1166.    <pre><code>4,999,999,999.99998, 4,999,999,999.99999,  5,000,000,000</code>
  1167. <code>     2386F26FC0FFEC,      2386F26FC0FFF6, 2386F26FC10000</code></pre></p>
  1168.    <h2 id='p-6'>Less formally</h2>
  1169.    <p>This includes “most” numbers that are used in practice, including prices, occurrence counts, size measurements, and so
  1170.    on.</p>
  1171.    <p>Examples of numbers that do <em>not</em> meet these criteria include AWS account numbers, some telephone
  1172.    numbers, and cryptographic keys/signatures. For those, Quamina just preserves the digits, whatever they may be, and in fact,
  1173.    this also usually ends up doing what people expect.</p>
  1174.    <h2 id='p-11'>Could we do better?</h2>
  1175.    <p>I think so. To start with, hex digits are an inefficient way to represent bits; there are
  1176.    <a href="https://en.wikipedia.org/wiki/Binary-to-text_encoding#Encoding_standards">many other options</a>.</p>
  1177.    <p>The current hex
  1178.    approach hasn’t changed since a very early version of Ruler because it’s never been a pain point.</p>
  1179.    <p>Speaking of Ruler, they recently landed a PR that lets them have 6 fractional digits as opposed to Quamina’s 5, simply by
  1180.    using decimal rather than binary arithmetic. It’s fast, too! This was made easier by the fact that Java has BigDecimal built in,
  1181.    while Go doesn’t. There are good open-source options out there, but I am extremely reluctant to accept dependencies in a package as
  1182.    low-level as Quamina. I don’t think matching more one more fractional digit justifies the cost of a dependency.</p>
  1183.    <h2 id='p-8'>“Q numbers?”</h2>
  1184.    <p>In Ruler, the data type is <code>ComparableNumber</code>. In Quamina I toyed with <code>comparableNumber</code> and
  1185.    <code>canonicalNumber</code> but neither is quite right and both produced excessively long and ugly variable and function
  1186.    names. So I decided to call them “Q numbers”, where Q is for Quamina. The code became noticeably more readable.</p>
  1187.    <p>While the set of Rationals is called “Q”, the only other significant use of the phrase “Q number” is some
  1188.    <a href="https://en.wikipedia.org/wiki/Q_(number_format)">weird old thing</a> out of Texas Instruments.</p>
  1189.    <h2 id='p-7'>Practicalities</h2>
  1190.    <p>The code to enforce the constraints and do the conversion isn’t that cheap. When I first naively dropped it in, I saw a
  1191.    nasty performance regression. Code optimization helped, but
  1192.    I realized then that it’s really important not to convert an incoming field that happens to be
  1193.    a JSON number into a Q number unless you know, first, that it meets the constraints and second, that the finite automaton we’re
  1194.    trying to match has a Pattern with a numerical match that also met the Q number constraints.</p>
  1195.    <p>The one moderately clever stroke here relies on the fact that Quamina has its own JSON parser,
  1196.    <a href="/ongoing/When/202x/2022/06/10/Quamina-Optimizing#p-5">because Reasons</a>. The parser obviously has to step its way
  1197.    through numbers, and it’s easy enough there to notice where the syntax characters like “.” and “e” are and cheaply figure out if
  1198.    the decimal is the right size.</p>
  1199.    <h2 id='p-9'>Conclusion</h2>
  1200.    <p>Quamina now knows numbers. It’s a little slower to match a 14-digit Q than a string like “20”, but finite automata are fast
  1201.    and anyhow, being right matters.</p>
  1202. </div></content></entry>
  1203.  
  1204. <entry>
  1205. <title>Lounge Penguin</title>
  1206. <link href='https://www.tbray.org/ongoing/When/202x/2024/06/23/Lounge-Penguin' />
  1207. <link rel='replies'        thr:count='2'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/06/23/Lounge-Penguin#comments' />
  1208. <id>https://www.tbray.org/ongoing/When/202x/2024/06/23/Lounge-Penguin</id>
  1209. <published>2024-06-23T12:00:00-07:00</published>
  1210. <updated>2024-06-23T12:00:00-07:00</updated>
  1211. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts/Music' />
  1212. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts' />
  1213. <category scheme='https://www.tbray.org/ongoing/What/' term='Music' />
  1214. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  1215. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  1216. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Lounge, as in a jazz club. Penguin, as in GoGo Pengin, a piano/bass/drums trio.     We caught their show at Jazz Alley in Seattle last week.      Maybe you should go hit a jazz lounge sometime</div></summary>
  1217. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1218.    <p>Lounge, as in a jazz club. Penguin, as in GoGo Pengin, a piano/bass/drums trio.
  1219.    We caught their show at Jazz Alley in Seattle last week.
  1220.    Maybe you should go hit a jazz lounge sometime.</p>
  1221.    <h2 id='p-1'>What happened was</h2>
  1222.    <p><a href="/ongoing/When/200x/2006/06/11/Now-We-Are-Four">My daughter turned eighteen</a> and graduated high school. She had heard
  1223.    that
  1224.    <a href="https://carseatheadrest.com/">Car Seat Headrest</a> was playing Seattle’s Woodland Park Zoo, and could tickets and a
  1225.    road trip (me buying and driving) be her present?  Seemed reasonable, and she found a friend to take along. I wouldn’t mind seeing the
  1226.    Headrests (decent indie rock stuff) but her party, her friend. I noticed that GoGo Penguin was playing Seattle’s Jazz Alley, and
  1227.    Lauren was agreeable to coming along for the ride and the show.</p>
  1228.    <p>I only know about GoGo Penguin because YouTube Music drops them into my default stream
  1229.    now and then. I’d thought “sounds good, maybe a little abstract”, couldn’t have named a song, but hey.</p>
  1230.    <h2 id='p-2'>The “Jazz Club” concept</h2>
  1231.    <p>You’ve seen it in a million old movies, and the
  1232.    <a href="https://en.wikipedia.org/wiki/Vic_Fontaine">Vic Fontaine</a> episodes of
  1233.    <a href="https://en.wikipedia.org/wiki/Star_Trek:_Deep_Space_Nine">ST:DS9</a>.
  1234.    The lights are low, the audience is sitting at tables with little lamps on them, the band’s on a thrust stage among the tables, there’s
  1235.    expected to be a soft background of clinking glasses and conversation. Some people are focusing in tight on the music, others are
  1236.    socializing at a respectfully low volume.</p>
  1237.    <p>Of course, usually a gunfight breaks out or an alien materializes on stage… no
  1238.    wait, that’s just on-screen not real-life.</p>
  1239.    <p>All jazz clubs serve alcohol<span class='dashes'> —</span> fancy cocktails, natch<span class='dashes'> —</span> and many will
  1240.    sell you dinner too.
  1241.    <a href="https://www.jazzalley.com/www-home/">Dimitriou’s Jazz Alley</a> in Seattle is a fine example.</p>
  1242.    <img src="https://www.tbray.org/ongoing/When/202x/2024/06/23/PXL_20240621_032418935.png" alt="GoGo Penguin at Demetriou’s Jazz Alley in Seattle" />
  1243.    <div class='caption'><p>GoGo Penguin at Jazz Alley; June 20th, 2024.<br/>
  1244.    Our table was in the balcony.</p></div>
  1245.    <p>We had a decent if conventional Pacific-Northwest dinner (crab and halibut), with a good bottle of local white.
  1246.    They’ve got things set up so most people have finished eating by the time the music starts. The seats were comfy. The decor
  1247.    was pleasing. The service was impeccable. I felt very grown-up.</p>
  1248.    <h2 id='p-3'>GoGo Penguin</h2>
  1249.    <p>They’re three youngish guys from Manchester.
  1250.    <a href="https://gogopenguin.co.uk">Their Web site</a> says they’re an “emotive, cinematic break-beat trio”. OK
  1251.    then. Piano/bass/drums is the canonical minimal jazz ensemble. Only they’re not minimal and it’s not jazz. I guess if you
  1252.    redefined “jazz” as complex rhythmically-sophisticated music featuring virtuoso soloing skills, well yeah.  Damn, those guys can
  1253.    play. But their music is heavily composed, not a lot of opportunities for anyone to stretch out and ride the groove.</p>
  1254.    <p>And it ain’t got that swing; can it still mean a thing?</p>
  1255.    <p>I guess so, because I enjoyed myself. There wasn’t a microsecond that was boring, plus the
  1256.    arrangements were super intelligent and kept surprising me.</p>
  1257.    <p>But most of all, the bass. Nick Blacka hit me harder than any bassist since I saw (and
  1258.    <a href="/ongoing/When/200x/2004/10/30/SlyAndRobbie">blogged</a>!) Robbie Shakespeare of
  1259.    Sly and Robbie in 2004.</p>
  1260.    <p>It’s really something special. It may be a stand-up acoustic bass, but it’s wired up so he can dominate the band’s sound when
  1261.    he reaches back for it (which he does neither too little nor too much). Plus the instrument’s acoustic texture roars out
  1262.    entirely unmarred, you can <em>feel</em> those strings and wood in your gut. He moves between bowing and plucking and banging and
  1263.    you hardly even notice because it’s always the right thing.</p>
  1264.    <p>I don’t wanna diss Chris Illingsworth on piano or Jon Scott on drums; both of them made me catch my breath. But it’s Blacka’s
  1265.    bass explosions that I took home with me.</p>
  1266.    <h2 id='p-5'>That swing?</h2>
  1267.    <p>These days my musical obsessions are Americana (i.e. bluegrass with pretensions) and old blues. The first of which also
  1268.    features instrumental complexity and virtuosity. And, if I’m being honest, both offer a whole lot more soul than Penguins.</p>
  1269.    <p>I respect what they’re doing. I’ll go see them again. But I wish they’d get the hell out from behind those
  1270.    diamond-bright razor-sharp arrangements and just <em>get down</em> sometimes.</p>
  1271.    <h2 id='p-6'>Next?</h2>
  1272.    <p>Lauren and I had real fun and left feeling a bit guilty that we’ve been ignoring Vancouver’s own jazz clubs. Not that I’m
  1273.    going to stop going to metal or post-punk or baroque concerts. But jazz clubs are a good grown-up option.</p>
  1274. </div></content></entry>
  1275.  
  1276. <entry>
  1277. <title>Epsilon Love</title>
  1278. <link href='https://www.tbray.org/ongoing/When/202x/2024/06/17/Epsilon-Love' />
  1279. <link rel='replies'        thr:count='2'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/06/17/Epsilon-Love#comments' />
  1280. <id>https://www.tbray.org/ongoing/When/202x/2024/06/17/Epsilon-Love</id>
  1281. <published>2024-06-17T12:00:00-07:00</published>
  1282. <updated>2024-06-20T21:57:52-07:00</updated>
  1283. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Quamina Diary' />
  1284. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  1285. <category scheme='https://www.tbray.org/ongoing/What/' term='Quamina Diary' />
  1286. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'><a href='https://github.com/timbray/quamina'>Quamina</a> was for a time my favorite among all my software contributions.     But then it stalled after I shipped 1.0 in January of 2023. First of all, I got busy with the     <a href='/ongoing/When/202x/2023/07/24/Workin-for-the-Man'>expert witness for Uncle Sam</a> gig and second, there was a horrible     problem in there that I couldn’t fix. Except for now I have! And I haven’t done much codeblogging recently.     So, here are notes on nondeterministic finite automata, epsilon     transitions, Ken Thompson, Golang generics, and     prettyprinting. If some subset of those things interests you, you’ll probably like this</div></summary>
  1287. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1288.    <p><a href="https://github.com/timbray/quamina">Quamina</a> was for a time my favorite among all my software contributions.
  1289.    But then it stalled after I shipped 1.0 in January of 2023. First of all, I got busy with the
  1290.    <a href="/ongoing/When/202x/2023/07/24/Workin-for-the-Man">expert witness for Uncle Sam</a> gig and second, there was a horrible
  1291.    problem in there that I couldn’t fix. Except for now I have! And I haven’t done much codeblogging recently.
  1292.    So, here are notes on nondeterministic finite automata, epsilon
  1293.    transitions, Ken Thompson, Golang generics, and
  1294.    prettyprinting. If some subset of those things interests you, you’ll probably like this.</p>
  1295.    <p>(Warning: if you’ve already had your hands on the theory and practice of finite automata,
  1296.    this may all be old hat.)</p>
  1297.    <p><i>[Update: This is kind of embarrassing. It looks like what this post refers to as an “epsilon” is not the same epsilon that
  1298.    features in the theory of finite automata. I mean, it still works well for where I’m using it, but I obviously need dig in
  1299.    harder and deeper.]</i></p>
  1300.    <h2 id='p-2'>Sidebar: What’s a Quamina?</h2>
  1301.    <p>I don’t think there’s much to be gained by duplicating Quamina’s
  1302.    <a href="https://github.com/timbray/quamina/blob/main/README.md">README</a> but in brief: “A
  1303.    fast pattern-matching library in Go with a large and growing pattern vocabulary and no dependencies outside Go’s standard
  1304.    libraries.” If you want much, much more, this
  1305.    <a href="/ongoing/What/Technology/Quamina%20Diary/">Quamina Diary</a> blog series has it.</p>
  1306.    <h2 id='p-1'>The problem</h2>
  1307.    <p>Combining too many patterns with wild-cards in them caused Quamina 1.0’s data structures to explode in size with a
  1308.    growth rate not far off the terrifying <code>O(2<sup>N</sup>)</code>, which meant that once you’d added much more than 20
  1309.    patterns you couldn’t add any more, because the add-pattern code’s runtime was <code>O(2<sup>N</sup>)</code> too.</p>
  1310.    <p>Those structures are state machines generally, “nondeterministic finite automata” (NFA’s) in particular.
  1311.    Which offer good solutions to many software problems,
  1312.    but when they get to be any size at all, are really hard to fit into a human mind.  So when I was looking at Quamina’s
  1313.    unreasonably-big automata and trying to figure out how they got that way, my brain was screaming
  1314.    “Stop the pain!”</p>
  1315.    <h2 id='p-3'>Lesson: Prettyprint!</h2>
  1316.    <p>At the point I stalled on Quamina, I’d started a refactor based on the theory that the NFAs were huge because
  1317.    of a failure to deduplicate state transitions. But the code I’d written based on that theory was utterly broken; it failed
  1318.    simple unit tests and I couldn’t see why.</p>
  1319.    <p>During the months when I was ignoring the problem, I privately despaired because I wasn’t sure I could ever crack it, and I
  1320.    couldn’t stomach more struggling with ad-hoc <code>Printf</code> and debugger output. So I decided to generate
  1321.    human-readable renditions of my automata. Given that, if I still couldn’t figure out
  1322.    what was going on, I’d have to admit I wasn’t smart enough for this shit and walk away from the problem.</p>
  1323.    <p>Which turned out to be a good call. Generating an information-dense but readable display was hard, and I decided
  1324.    to be ruthless about getting the spaces and punctuation in the right
  1325.    places. Because I didn’t want to walk away.</p>
  1326.    <p>Back in the day, we used to call this “prettyprinting”.</p>
  1327.    <p>It worked! First of all, my prettyprinter showed me that the automata emitted based on my deduplication
  1328.    theory were just wrong, and what was wrong about them, and I found that code and fixed it.</p>
  1329.    <p>Bad news: My deduplication theory was also just wrong.
  1330.    Good news: My prettyprinter provided unavoidable proof of the wrongness
  1331.    and made me go back to first principles.</p>
  1332.    <p>And I just landed a PR that cleanly removed the state explosion.</p>
  1333.    <h2 id='p-8'>Free advice</h2>
  1334.    <p>I’ll show off the prettyprinter output below where I dig into the state-explosion fix. But for the
  1335.    moment, a recommendation: If you have a data structure that’s not Working As Intended and is hard to grok, go hide for a couple
  1336.    of days and write yourself a prettyprinter. Prettyprinting is an intelligence amplifier.
  1337.    Your Future Self will thank you heartily.</p>
  1338.    <h2 id='p-4'>“Back to first principles”?</h2>
  1339.    <p>The single best write-up on NFA and regex
  1340.    basics that I’ve ever encountered is
  1341.    <a href="https://swtch.com/~rsc/regexp/regexp1.html">Regular Expression Matching Can Be Simple And Fast (but is slow in Java,
  1342.    Perl, PHP, Python, Ruby, ...)</a> by
  1343.    <a href="https://swtch.com/~rsc/">Russ Cox</a>. It’s a discussion of, and reflection on, the regular expression library
  1344.    constructed by <a href="https://en.wikipedia.org/wiki/Ken_Thompson">Ken Thompson</a> in the mid-Sixties, before he got mixed up
  1345.    in Unix.</p>
  1346.    <p>What’s annoying is that I had read this before I started wiring NFAs into Quamina, but ignored most of its important lessons
  1347.    due to a combination of not understanding them and thinking that my existing code could do what Cox described. A couple of
  1348.    weeks ago I went back and read it again, and it all made perfect sense and showed me the way forward. So I guess the lesson is that
  1349.    if you’re not Ken Thompson, you’re going to have trouble understanding what he did until you’ve tried and failed yourself?
  1350.    </p>
  1351.    <p>So, major thanks to Ken for this (and Unix and other things too) and to Russ for the write-up.</p>
  1352.    <h2 id='p-5'>Epsilon transitions</h2>
  1353.    <p>These are the magic bullet that make NFA’s work. Quamina didn’t have them, now it does. There are other bits and
  1354.    pieces but that’s the core of the thing.</p>
  1355.    <p>I think the easiest way to explain is by showing you an NFA as displayed by Quamina’s new prettyprinter. It matches the
  1356.    regular expression <code>"x.*9"</code><span class='dashes'> —</span> note that the
  1357.    <code>"</code> delimiters are part of the pattern:</p>
  1358.    <pre style="font-family: monospace; font-weight: bold; font-size:110%;line-height:150%;"> 758[START HERE] '"' → 910[on "]
  1359. 910[on "] 'x' → 821[gS]
  1360. 821[gS] ε → 821[gS] / '9' → 551[gX on 9]
  1361. 551[gX on 9] '"' → 937[on "]
  1362. 937[on "] 'ℵ' → 820[last step]
  1363. 820[last step]  [1 transition(s)]</pre>
  1364.    <ul>
  1365.      <li><p>There’s an API to attach labels to states as you build automata, which as a side-effect gives each a random  3-digit
  1366.      number too. This is done in a way that can be turned into a no-op at production time.</p></li>
  1367.      <li><p><b>758</b>: The start state; the only character that does anything is the opening <code>"</code> delimiter which
  1368.      transitions to state 910.</p></li>
  1369.      <li><p><b>910</b>: You get here when you see the <code>"</code> and the only exit is if you see an <code>x</code>, which
  1370.      moves to 821.</p></li>
  1371.      <li><p><b>821</b>: This state is the “glob” <code>*</code> operator. <code>gS</code> in its label stands for “glob spin”. It
  1372.      has an "epsilon" (<code>ε</code>) transition to itself. In Computer-Science theory, they claim that the epsilon transition
  1373.      can occur at any time, spontaneously, la-di-da. In programming practice, you take an epsilon transition for every input
  1374.      character. 821 also has an ordinary transition on <code>9</code> to state 551.</p>
  1375.      <p>This possibility of having multiple transitions out of a state on the same input symbol,
  1376.      and the existence of epsilon transitions, are the defining characteristics that make NFAs “nondeterministic”.</p></li>
  1377.      <li><p><b>551</b>: Its label includes <code>gX</code> for “glob exit”. The only transition is on the closing <code>"</code>
  1378.      delimiter, to 937.</p></li>
  1379.      <li><p><b>937</b> has only one transition, on <code>ℵ</code> (stands for the reserved value Quamina inserts to signal
  1380.      the end of input) to 820.</p></li>
  1381.      <li><p><b>820</b> doesn’t do anything, but the <code>[1 transition(s)]</code> label means that if you reach here you’ve
  1382.      matched this field’s value and can transition to working on the next field.</p></li>
  1383.    </ul>
  1384.    <p>Now I’m going to display the prettyprint again so you can look at it as you read the next paragraph.</p>
  1385.    <pre style="font-family: monospace; font-weight: bold; font-size:110%;line-height:150%;"> 758[START HERE] '"' → 910[on "]
  1386. 910[on "] 'x' → 821[gS]
  1387. 821[gS] ε → 821[gS] / '9' → 551[gX on 9]
  1388. 551[gX on 9] '"' → 937[on "]
  1389. 937[on "] 'ℵ' → 820[last step]
  1390. 820[last step]  [1 transition(s)]</pre>
  1391.    <p>A little thought shows how the epsilon-transition magic works. Suppose the input string is <code>"xyz909"</code>. The code
  1392.    will match the leading <code>"</code> then <code>x</code> and hit state 821. When it sees <code>y</code> and <code>z</code>, the
  1393.    only thing that
  1394.    happens is that the epsilon transition loops back to 821 every time. When it hits the first <code>9</code>, it’ll advance to
  1395.    551 but than stall out because the following character is <code>0</code> which doesn’t match the only path forward through
  1396.    <code>"</code>. But the epsilon transition keeps looping and when the second <code>9</code> comes along it’ll proceed
  1397.    smoothly through 551, 937, and 820, signaling a match. Yay!</p>
  1398.    <p>So now, I have a fuzz test which adds a pattern for each of about thirteen thousand  5-letter words, with one <code>*</code>
  1399.    embedded in each at a random offset, including the leading and trailing positions. The add-pattern code hardly slows down at
  1400.    all. The <em>matching</em> code slows down a lot,
  1401.    to below 10,000/second, in stark contrast to most Quamina instances, which can achieve millions of matches/second.</p>
  1402.    <p>I’m sort of OK with this trade-off; after all, it’s matching 10K-plus patterns!  I’m going to work on optimizing it, but I
  1403.    have to accept that the math, as in finite-automata theory, might be against
  1404.    me. But almost certainly there are <em>some</em> optimizations to be had. There are possibilities suggested by Cox’s description
  1405.    of Thompson’s methods. And the search for paths forward will likely be good blog fodder.  Yay!</p>
  1406.    <h2 id='p-6'>Ken again</h2>
  1407.    <p>When I re-read Russ Cox’s piece, I was looking at the pictures and narrative, mostly ignoring the C code. When everything
  1408.    was working, I went back and was irrationally thrilled that my bottom-level function for one state traversal had the same name
  1409.    as Ken Thompson’s: <code>step()</code>.</p>
  1410.    <p>Also, when you process an NFA, you can be in multiple states at once; see the <code>"xyz909"</code> example above. When
  1411.    you’re in multiple states and you process an input symbol, you might end up in zero, one, or many new states.
  1412.    Russ writes, of Ken Thompson’s code, “To avoid allocating on every iteration of the loop, <code>match</code> uses two
  1413.    preallocated lists <code>l1</code> and
  1414.    <code>l2</code> as <code>clist</code> and <code>nlist</code>, swapping the two after each step.”</p>
  1415.    <p>Me too! Only mine are called <code>currentStates</code> and <code>nextStates</code> because it’s 2024.</p>
  1416.    <p>And thereby hangs a blog or maybe more than one. Because traversing the NFA is at Quamina’s white-hot center. You really
  1417.    REALLY don’t want to be allocating memory in that code path. Which should be straightforward. But it’s not, for interesting
  1418.    reasons that raise optimization problems I’m just starting to think about, but you’ll probably hear all about it when I do.</p>
  1419.    <h2 id='p-7'>Un-generic</h2>
  1420.    <p>In the process of moving Quamina from DFAs to mixed DFA/NFA to pure-NFA I adopted and then abandoned Go’s generics.
  1421.    They hate me. Or I’m not smart enough. Or something. I
  1422.    <a href="/ongoing/When/202x/2022/05/14/Golang-Generics">wrote about the experience</a> back in 2022 and while that piece ended
  1423.    inconclusively, I am personally much happier with generics-free Go code. Maybe they make other people happy.</p>
  1424.    <h2 id='p-9'>Hard to understand</h2>
  1425.    <p>And then finally, there’s this one function I wrote in June 2022, doesn’t matter what it does. It has a a comment at the top that begins:
  1426.    “Spookeh. The idea is that…” and goes on for a long paragraph which, well, I can’t understand. Then I look at the code and think
  1427.    “that can’t work.” I keep thinking of sequences that should send it off the rails and write the unit tests and they fail to fail,
  1428.    and I use the prettyprinter and the NFA it generates is ruthlessly correct. I go back and look at it every few days and end up
  1429.    shaking my head. This is making me grumpy.</p>
  1430.    <p>But after all, I did write, in a
  1431.    <a href="/ongoing/When/202x/2022/05/19/Quamina-Matchers#p-7">previous Quamina Diary episode</a>: “The observation that computer
  1432.    programmers can build executable abstractions that work but they then have trouble understanding is not new and not
  1433.    surprising. Lots of our code is smarter than we are.”</p>
  1434.    <p>But I’ll figure it out. And it’s nice to have interesting computer-programming stuff to blog about.</p>
  1435.    <!--
  1436.    <p>computer memory is organized in sequences of numbers</p>
  1437.    <p>memory thrashing</p>
  1438.    -->
  1439. </div></content></entry>
  1440.  
  1441. <entry>
  1442. <title>Wikipedia Pain</title>
  1443. <link href='https://www.tbray.org/ongoing/When/202x/2024/06/15/Wikipedia-Pain' />
  1444. <link rel='replies'        thr:count='7'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/06/15/Wikipedia-Pain#comments' />
  1445. <id>https://www.tbray.org/ongoing/When/202x/2024/06/15/Wikipedia-Pain</id>
  1446. <published>2024-06-15T12:00:00-07:00</published>
  1447. <updated>2024-06-16T09:37:06-07:00</updated>
  1448. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Publishing/Reference' />
  1449. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  1450. <category scheme='https://www.tbray.org/ongoing/What/' term='Publishing' />
  1451. <category scheme='https://www.tbray.org/ongoing/What/' term='Reference' />
  1452. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>There are voices<span class="dashes"> —</span> some loud and well-respected<span class="dashes"> —</span> who argue that     Wikipedia is deeply flawed, a hellscape of psychotic editors and contempt for expertise. I mostly disagree, but     those voices deserve, at least, to be heard</div></summary>
  1453. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1454.    <p>There are voices<span class='dashes'> —</span> some loud and well-respected<span class='dashes'> —</span> who argue that
  1455.    Wikipedia is deeply flawed, a hellscape of psychotic editors and contempt for expertise. I mostly disagree, but
  1456.    those voices deserve, at least, to be heard.</p>
  1457.    <p><i>[Note: There’s a companion blog post,
  1458.    <a href="Edit-War">Sex Edit War!</a>, about  my own experience in a Wikipedia Edit War. (I won! It was fun!)
  1459.    I hope it’ll make some of this narrative more concrete.]</i></p>
  1460.    <h2 id='p-1'>Background</h2>
  1461.    <p>If you look at this post’s
  1462.    <a href="/ongoing/What/Technology/Publishing/Reference/">Reference Publishing</a> topic, you’ll see a lot of
  1463.    Wikipedia-related material. I was one of its early defenders against the early-days waves of attackers who compared it to a
  1464.    <a href="/ongoing/When/200x/2004/11/16/McHenry">public toilet</a> and its editors to the Khmer Rouge.</p>
  1465.    <p>I should also disclose that, over the years, I have made some 2,300 Wikipedia edits,
  1466.    <a href="https://xtools.wmcloud.org/pages/en.wikipedia.org/TimBray">created seven articles</a>, and (what makes me happiest)
  1467.    <a href="https://glamtools.toolforge.org/glamorous.php?doit=1&amp;category=Photographs_by_Tim_Bray&amp;use_globalusage=1&amp;depth=3&amp;show_details=1&amp;projects%5Bwikipedia%5D=1&amp;projects%5Bwikimedia%5D=1&amp;projects%5Bwikisource%5D=1&amp;projects%5Bwikibooks%5D=1&amp;projects%5Bwikiquote%5D=1&amp;projects%5Bwiktionary%5D=1&amp;projects%5Bwikinews%5D=1&amp;projects%5Bwikivoyage%5D=1&amp;projects%5Bwikispecies%5D=1&amp;projects%5Bmediawiki%5D=1&amp;projects%5Bwikidata%5D=1&amp;projects%5Bwikiversity%5D=1">contributed
  1468.    49 images</a> which have been used, in aggregate, 228 times.</p>
  1469.    <p>I say all this to acknowledge that I am probably predisposed to defend Wikipedia.</p>
  1470.    <h2 id='p-2'>What happened was…</h2>
  1471.    <p>Somebody spoke up on the Fediverse, saying “I wonder if reporters know that Wikipedia hallucinates too??”
  1472.    I’m not giving that a link, since they followed up with a post asserting that ChatGPT is better than Wikipedia. Life’s too short
  1473.    for that.</p>
  1474.    <p>Anyhow,
  1475.    <a href="https://phanpy.social/#/cosocial.ca/s/112581434393938844">I replied</a> “The difference is, errors in Wikipedia tend to get
  1476.    systematically fixed. Sometimes it takes more work than it should, but the vast majority of articles are moving in the right
  1477.    direction a vast majority of the time.” Much discussion ensued; follow the threads.</p>
  1478.    <p>Shortly thereafter, the redoubtable JWZ
  1479.    <a href="https://phanpy.social/#/cosocial.ca/s/112595065934183929">complained</a> about an edit to his page and
  1480.    <a href="https://phanpy.social/#/cosocial.ca/s/112596132485364087">I spoke up</a> noting that the edit had been reversed, as bad
  1481.    edits (in my experience) usually are.  That conversation branched out vigorously, dozens of contributions.  Feel free to trawl through
  1482.    the Fediverse threads, but you don’t have to, I’ll summarize.</p>
  1483.    <h2 id='p-3'>Gripe: Bad editors</h2>
  1484.    <p>This kept coming back.</p>
  1485.    <ul>
  1486.      <li><p><a href="https://phanpy.social/#/cosocial.ca/s/112596190950148931">Jamie Zawinski:  I just find the culture of the editors
  1487.      intolerable.</a></p></li>
  1488.      <li><p><a href="https://phanpy.social/#/cosocial.ca/s/112603672166068677">Ruben Schade: I didn’t want to draw the ire of those horrible
  1489.      admins.</a></p></li>
  1490.      <li><p><a href="https://phanpy.social/#/cosocial.ca/s/112597984955005878">Dave Slusher: The editor culture demonstrably
  1491.      contains decision makers who ain't that bright and are pretty lazy.</a></p></li>
  1492.    </ul>
  1493.    <p>I dunno. I don’t want to gaslight those people; if that’s the experience they had, that’s the experience they had. My own
  1494.    experience is different: The editors I’ve interacted with have generally been friendly and supportive, and often exceptionally
  1495.    skilled at digging up quality citations. But I think that these reports are something Wikipedia should worry about.</p>
  1496.    <h2 id='p-4'>Gripe: Disrespect of expertise</h2>
  1497.    <p>By number and volume of complaints, this was the #1 issue that came up in those threads:</p>
  1498.    <ul>
  1499.      <li><p><a href="https://phanpy.social/#/cosocial.ca/s/112596279133214378">Brian Dear: Pantheon published my book in
  1500.      2017. For years I tried to add to the paltry Wikipedia entries for everything from PLATO, plasma panels, to early MUDs,
  1501.      instant msging, but no: Wikipedia editors deleted it all (“not authoritative”). Screw ‘em.</a></p></li>
  1502.      <li><p> <a href="https://phanpy.social/#/cosocial.ca/s/112596450752955593">Dan O’Neill: An editor argued with me about the
  1503.      history of my own company.</a></p></li>
  1504.      <li><p> <a href="https://phanpy.social/#/cosocial.ca/s/112597271195266197">Zawinski: Wikipedia specifically rejects domain experts
  1505.      until someone who knows nothing cites them elsewhere.</a></p></li>
  1506.      <li><p><a href="https://phanpy.social/#/cosocial.ca/s/112599383637496615">Alex Rosenberg: So many mistakes in early pages about PS3
  1507.      that I tried to get corrected as a primary source, but some random kiddie blogger's guess as to what an acronym stood for was
  1508.      more valuable to the editors.</a></p></li>
  1509.    </ul>
  1510.    <p>I generally disagree with these takes. Wikipedia not only respects but <em>requires</em> expert support for its
  1511.    content. However, it uses a very specific definition of “expert”: Someone who can get their assertions published in one or more
  1512.    <a href="https://en.wikipedia.org/wiki/Wikipedia:Reliable_sources">Reliable Sources</a>.</p>
  1513.    <p>I think that if you’re about to
  1514.    have an opinion about Wikipedia and expertise and citations, you should give that Reliable-Sources article a careful read first.
  1515.    Here’s why: It is at the white-hot center of any conversation about what Wikipedia should and should not say. Since Wikipedia is
  1516.    commonly the
  1517.    top result for a Web search, and since a couple of generations of students have been taught to consult but not cite it,
  1518.    the article is central to what literate people consider to be true.</p>
  1519.    <p>Let’s consider the complaints above. Mr Dear literally Wrote the Book. But, I dunno. I went and looked at the PLATO article
  1520.    and subjects linked to it, and, well, it looks good to me? It cites Mr Dear’s book but just once. Maybe the editors didn’t think
  1521.    Mr Dear’s book was very good? Maybe Dear says controversial things that you wouldn’t want to publish without independent
  1522.    evidence? The picture is inconclusive.</p>
  1523.    <p>As for Mr O’Neill’s complaint, no sympathy. Given the social structure of capitalism, the employees and leadership of a
  1524.    company are the <em>last</em> people who should be considered Reliable Sources on that company. Particularly on anything that’s
  1525.    remotely controversial.</p>
  1526.    <p>Mr Zawinski is upset that the person who chooses citations from Reliable Sources “knows nothing”, which I take to be an
  1527.    abbreviation for “is not a subject-matter expert”. There’s some truth here.</p>
  1528.    <p>When it comes to bald statements of fact, you
  1529.    don’t need to be an expert; If more than one quality magazine or academic journal says that the company was
  1530.    incorporated in 1989, you don’t need to know anything about the company or its products to allow “founded in 1989” into an article.</p>
  1531.    <p>On the other hand, I think we can all agree that people who make significant changes on articles
  1532.    concerning complex subjects should know the turf. My impression is that, for <em>academic</em> subjects, that condition is
  1533.    generally met.</p>
  1534.    <p>Mr Rosenberg, once again, is upset that his <em>personal</em> expertise about the PS3 is being disregarded in favor of
  1535.    material sourced from a gamer blog. I’d have to know the details, but the best possible outcome would be Mr Rosenberg
  1536.    establishing his expertise by publishing his narrative in a Reliable Source.</p>
  1537.    <h2 id='p-8'>Bad Pattern</h2>
  1538.    <p>There’s a pattern I’ve seen a few times where a person sees something in Wikipedia in an area where they think they’re
  1539.    knowledgeable and think it’s wrong and decide “I’ll just fix that.” Then their edits get bounced because they don’t include
  1540.    citations. Even though they’re an “expert”. Then that person stomps away fuming publicly that Wikipedia is crap.  That’s
  1541.    unfortunate, and maybe Wikipedia should change its tag-line from “anyone can edit” to “anyone who’s willing to provide citations
  1542.    can edit.”</p>
  1543.    <h2 id='p-6'>Implications</h2>
  1544.    <p>This policy concerning expertise has some consequences:</p>
  1545.    <ol>
  1546.      <li><p>The decision on who is and isn’t an expert is by and large outsourced to the editorial staff of Reliable
  1547.      Sources.</p></li>
  1548.      <li><p>There are ferocious debates among editors about which sources are Reliable
  1549.      and which are not, in the context of some specific article. Which is perfectly appropriate and necessary.  For example, last time I
  1550.      checked, Fox News is considered
  1551.      entirely Reliable on the finer points of NFL football, but not at all on US politics.</p></li>
  1552.      <li><p>There are many things which people know to be true but aren’t in Wikipedia and likely never will be, because no
  1553.      Reliable Source has ever discussed the matter.  For example, I created the
  1554.      <a href="https://en.wikipedia.org/wiki/East_Van_Cross">East Van Cross</a> article, and subsequently learned the story
  1555.      of the cross’s origin. I found it entirely convincing but it was from an guy I met at a friend’s party who was a student at the high
  1556.      school where and when the graphic was first dreamed up. I looked around but found no Reliable Sources saying anything on the
  1557.      subject. I doubt it’ll ever be in Wikipedia.</p></li>
  1558.    </ol>
  1559.    <p>What do you think of those trade-offs? I think they’re pretty well OK.</p>
  1560.    <p>The notion that anyone should be allowed to add uncited
  1561.    assertions to Wikipedia because <em>they</em> think they’re an expert strikes me as simultaneously ridiculous and dangerous.</p>
  1562.    <h2 id='p-5'>Real problems</h2>
  1563.    <p>Obviously, Wikipedia isn’t perfect. There are two problems in particular that bother me all the time, one small, one big.</p>
  1564.    <p>Small first: The editor culture is a thicket of acronyms and it’s hard to keep them straight. I have considered, in some future
  1565.    not-too-fierce editorial debate, saying “Wait, WP:Potrezebie says you can’t say that!” Then see if anyone calls me on it.</p>
  1566.    <p>The big problem: The community of editors is heavily male-dominated, and there have repeatedly been credible accusations of misogyny.
  1567.    I have direct experience: I created the article for
  1568.    <a href="https://en.wikipedia.org/wiki/Sarah_Smarsh">Sarah Smarsh</a>, because we read her excellent book
  1569.    <a href="https://en.wikipedia.org/wiki/Heartland_(Smarsh_book)">Heartland</a> in my book club, then I was shocked to find no
  1570.    entry. Despite the existence of that mainstream-published and well-reviewed book, and the fact that she had published in <cite>The
  1571.    Guardian</cite> and
  1572.    the <cite>Columbia Journalism Review</cite>, some other editor decreed that that was insufficient notability.</p>
  1573.    <p>At the time, I
  1574.    reacted by gradually accumulating more and more citations and updating the draft.  Eventually she published another book and the
  1575.    argument was over. These days, in that situation I would raise holy hell and escalate the obstruction up the Wikipedia
  1576.    stack.</p>
  1577.    <p>To Wikipedia’s credit, its leadership knows about this problem and gives the appearance of trying to improve it. I don’t know
  1578.    the details of what they’re trying and whether they’re moving the needle at all.  But it’s clearly still a problem.</p>
  1579.    <h2 id='p-9'>Once again…</h2>
  1580.    <p>I stand by what I said in December 2004: Wikipedia dwarfs its critics.</p>
  1581. </div></content></entry>
  1582.  
  1583. <entry>
  1584. <title>Sex Edit War!</title>
  1585. <link href='https://www.tbray.org/ongoing/When/202x/2024/06/15/Edit-War' />
  1586. <link rel='replies'        thr:count='2'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/06/15/Edit-War#comments' />
  1587. <id>https://www.tbray.org/ongoing/When/202x/2024/06/15/Edit-War</id>
  1588. <published>2024-06-15T12:00:00-07:00</published>
  1589. <updated>2024-06-16T09:21:40-07:00</updated>
  1590. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Publishing/Reference' />
  1591. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  1592. <category scheme='https://www.tbray.org/ongoing/What/' term='Publishing' />
  1593. <category scheme='https://www.tbray.org/ongoing/What/' term='Reference' />
  1594. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>In January 2010 I drove twenty-five minutes across Vancouver to the University of British Columbia’s main library, with the goal     of crushing an opponent in a Wikipedia edit war. The battleground was the entry on     <a href='https://en.wikipedia.org/wiki/T._E._Lawrence'>T.E. Lawrence</a> (better known as Lawrence of     Arabia). I won that war.  As a consequence, I consider myself the world’s leading living expert on Lawrence’s sexuality</div></summary>
  1595. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1596.    <p>In January 2010 I drove twenty-five minutes across Vancouver to the University of British Columbia’s main library, with the goal
  1597.    of crushing an opponent in a Wikipedia edit war. The battleground was the entry on
  1598.    <a href="https://en.wikipedia.org/wiki/T._E._Lawrence">T.E. Lawrence</a> (better known as Lawrence of
  1599.    Arabia). I won that war.  As a consequence, I consider myself the world’s leading living expert on Lawrence’s sexuality. </p>
  1600.    <p><i>[Note: This is posted alongside
  1601.    <a href="/ongoing/When/202x/2024/06/15/Wikipedia-Pain">Wikipedia Pain</a>, which is about the issues of truth and expertise in
  1602.    Wikipedia editing, in an effort to share what the process feels like from the inside.]</i></p>
  1603.    <p>Why Lawrence, anyhow? My
  1604.    <a href="https://www.textuality.com/BillBray/">Dad</a>, an Alberta farm boy, became a Professor of Agriculture, and spent most
  1605.    of his career in the Third World, much of it in Lebanon and Jordan. As a result, I spent my youth there, with plentiful
  1606.    opportunities for touristing all over the Middle East, including many of the spots that appear in Lawrence’s monumental war
  1607.    memoir <cite>Seven Pillars of Wisdom</cite>.</p>
  1608.    <p>I ran across <cite>Seven Pillars</cite> in college and devoured it, from time to time thinking “I’ve been there!”  While it’s full of
  1609.    camel charges, train-bombings, and other Ripping Yarns, it’s a difficult book, not a light read at all. But I enjoyed it and was
  1610.    left wondering who this guy was. So in the course of time I read Lawrence’s other works, some biographies (there are many) and
  1611.    especially, the collected letters. </p>
  1612.    <p>Lawrence was an avid correspondent, sending letters almost like we do emails, multiple times most days.  I suspect that a
  1613.    whole lot of the Lawrence biographers got the idea by reading the letters and like me thinking “who is this guy?” You might want
  1614.    to do a little Lawrence reading.</p>
  1615.    <p>Conducting archeology on my blog reveals that I apparently noticed Wikipedia in 2003 and had started contributing to the
  1616.    Lawrence article by 2004; in that year I also
  1617.    <a href="/ongoing/When/200x/2004/08/31/Wikipedia">wrote</a> “Maybe the Wikipedia is a short-lived fad, maybe it’ll get better, maybe
  1618.    it’ll get worse, but I was surprised that nobody pointed this out: The Wikipedia is beautiful. It’s an unexpected and
  1619.    unexplainable triumph of collective creativity and of order over entropy. I hope it lasts a long time, and those who criticize
  1620.    it Just Don’t Get It.”</p>
  1621.    <p>At that time popular opinions of The Encyclopedia That Anyone Can Edit ranged from a headshaking blow-off of the idea’s obvious
  1622.    craziness to active fear and hostility. British technology journalist Andrew Orlowski once referred to Wikipedians as
  1623.    “Khmer Rouge in daipers” (sic). I became a partisan, wading into the ring against figures as eminent as Bob McHenry, former Editor
  1624.    of the Britannica, who compared Wikipedia to a public toilet: “you can’t be sure who was there before you.” I enjoyed rolling out my
  1625.    rhetorical and polemical cannon and firing back. From
  1626.    <a href="/ongoing/When/200x/2004/12/06/Trustipedia">December 2004</a>: “One thing is sure: the Wikipedia
  1627.    dwarfs its critics.”</p>
  1628.    <p>It must be said that back then, the critics had a point. Those of us who waded in early often found entries about
  1629.    major subjects of history or culture which were a stinking mess.  Lawrence was one such; a farrago of conspiracy theories and
  1630.    thinly-sourced fantasies.</p>
  1631.    <h2 id='p-1'>Sex!</h2>
  1632.    <p>In particular the section about Lawrence’s sexuality, a subject much discussed by his biographers and occasionally in the popular
  1633.    press. The amount of time I’ve put into making this fact-based would probably be regarded as ridiculous by most sane people. <i>[Would
  1634.    they be wrong? -Ed.] [Pretty sure. -T.]</i></p>
  1635.    <p>I have plenty of by-and-about-Lawrence books on my shelves and had read more or less every published letter, which I thought
  1636.    gave me a fair claim to knowing him better as a person than your average Wikipedia editor. By dint of dogged incremental
  1637.    citation-backed edits, I was making good progress by 2009 at introducing order to the chaos.</p>
  1638.    <h2 id='p-3'>Edit!</h2>
  1639.    <p>Editing Wikipedia involves regular, often intense, disputes about what should be said. These take place on the “Talk” page
  1640.    that is associated with each article.  For a contentious entry, such as Lawrence’s had become, the Talk page can become huge,
  1641.    much larger than the entry itself.</p>
  1642.    <p>In these disputes, the criteria that matter are “notability” and “verifiability”.  To be included, a subject must be notable,
  1643.    i.e. worth mentioning.  When is something notable? If, and only if, there are mentions of the subject in multiple credible
  1644.    mainstream sources. Further, any assertion must be verifiable, i.e. there is evidence to establish that the claims in the
  1645.    material are correct. Both criteria are addressed by providing citations from
  1646.    <a href="https://en.wikipedia.org/wiki/Wikipedia:Reliable_sources">Reliable Sources</a>.</p>
  1647.    <p>On the subject of verifiability, Wikipedia says to the world: <em>Any material that is not verifiable will eventually be
  1648.    removed.</em> That tenet gives a warm glow to those of us who live on the Internet and care a lot about truth and untruth.</p>
  1649.    <p>The subject at hand was homosexuality. First, had Lawrence been gay? Second, what was his attitude toward gay people?
  1650.    Remember, this is a man who died in 1935; in his lifetime, homosexuality was publicly much disapproved-of and in fact
  1651.    specifically forbidden by law.</p>
  1652.    <p>I thought I had the facts on my side. Whatever Lawrence’s orientation, there was no evidence of consensual intimacy with
  1653.    anyone of any gender, and he repeatedly and explicitly denied, in private correspondence, any experience of sex.</p>
  1654.    <p>On the other hand, his writing includes multiple warm, approving remarks about male/male sexual relationships.  So I thought
  1655.    the case for “celibate and tolerant” was pretty well open and shut.</p>
  1656.    <h2 id='p-2'>War!</h2>
  1657.    <p>But then I found I had an adversary.</p>
  1658.    <p>“Factuarius” – the handle of another active Wikipedia editor – came to fight. For reasons opaque to me, Factuarius was
  1659.    pretty convinced that Lawrence had been gay and/or disapproved of homosexuality. He was able to assemble citations where people
  1660.    had alleged relationships between Lawrence and one or another male person, but this was well-plowed ground; biographers had
  1661.    found an absence of evidence for the relationships and reasonably convincing reasons to doubt their having happened.</p>
  1662.    <p>Factuarius decided that Lawrence’s having disapproved of homosexuality was the hill he was going to die on.  He triumphantly
  1663.    produced two citations that supported his position, declared victory, and told me to stand down.</p>
  1664.    <p>The first was “Khondakar Golam Mowla, 2008 p. 258”. The book is <cite>The Judgment Against
  1665.    Imperialism, Fascism and Racism Against Caliphate and Islam: Volume 1</cite>. You can buy it from Amazon for $36.49 as I write this. It
  1666.    turns out it is self-published at “AuthorHouse” and that its Foreword denounces, among other things, “Ataturk, a secret
  1667.    Jew”. The tone generally follows from there. I pointed out to Factuarius that I could go to AuthorHouse and generate a book
  1668.    claiming Lawrence was from Mars.</p>
  1669.    <p>That left him hotly defending his last reference, a Lawrence letter cited in “Homosexuality and Orientalism: Edward
  1670.    Carpenter's journey to the east, P. K. Bakshi, <cite>Prose Studies</cite>, Volume 13, Issue 1 May 1990, pages 151-177,
  1671.    Routledge”.  Seeing no
  1672.    alternative, I made that drive over to the nearest big University research library.</p>
  1673.    <p>It took a while to track down <cite>Prose Studies</cite>, whose dusty and clearly-unvisited volumes occupy quite a few
  1674.    shelf-feet. It was founded in 1977 and the Internet tells me it’s still publishing. I really don’t know what this journal is for
  1675.    or what effect on
  1676.    the world, if any, its existence is designed to achieve. <i>[Arrogant, much? -Ed.] [Trying to be polite. -T.]</i></p>
  1677.    <p>Sure enough, the article about
  1678.  
  1679.    <a href="https://en.wikipedia.org/wiki/Edward_Carpenter">Edward Carpenter</a> was there in the May 1990 volume. I read it. I
  1680.    photographed (badly, with a
  1681.    2010 phone-cam) the title and index pages to prove that I had done so. The article mentioned Lawrence twice, suggesting in an
  1682.    off-handed way that he was an example of English fascination with homosexuality and “the Orient”.  But there was nothing there
  1683.    that looked like Factuarius’ citation.</p>
  1684.    <h2 id='p-4'>Victory!</h2>
  1685.    <p>I was left happy for multiple reasons. It is a wonderful thing that research libraries exist and preserve academic journals
  1686.    for their own sake, whether or not any human will ever consult their pages. It was pretty cool playing scholarly sleuth in the
  1687.    quiet passages of the library. Best of all, Factuarius retired silently from the fray.</p>
  1688.    <p>Which was actually a pretty minor scuffle by Wikipedia standards. There is a hilarious page entitled
  1689.  
  1690.    <a href="https://en.wikipedia.org/wiki/Wikipedia:Lamest_edit_wars">Wikipedia:Lamest edit wars</a>, which I recommend
  1691.    just for fun.  It even categorizes them. The first-appearing category is
  1692.    “Ethnic and national feuds”, featuring the titanic struggles over the ancestries of Frédéric Chopin and Freddie
  1693.    Mercury. So far, none of these has metamorphosed into a real actual nation-against-nation shooting war, but I’m not saying it
  1694.    couldn’t happen.</p>
  1695.    <p>Eventually I took the trouble of collecting every citable fact about Lawrence’s sexuality that I could find in all the known
  1696.    published resources – online search in the Gutenberg Project and various other sources helped. I published them in a blog piece
  1697.    entitled
  1698.    <a href="/ongoing/When/200x/2009/12/20/Sexuality-of-T-E-Lawrence">Sex and T.E. Lawrence</a>, which has been useful in subsequent
  1699.    (much less dramatic) editing disagreements.</p>
  1700.    <p>Finally, I gave a talk at a social-media conference sometime in the 2000s entitled <cite>Editing Wikipedia</cite> in which I
  1701.    had great fun relating this episode, and I think the audience did too. In particular, reading out spicy passages
  1702.    illustrating Lawrence’s
  1703.    real kink – there’s strong evidence that he was a masochist. For example, in later life, he paid to have himself whipped
  1704.    “severely enough to produce a seminal emission”.</p>
  1705.    <p>The effect, at the end of all this was that material that was not verifiable – an assertion about a historically-notable
  1706.    person’s viewpoint on a particular issue – was, as it should be, removed from Wikipedia.  </p>
  1707.    <p>Also, pursuing the truth can be its own reward.</p>
  1708. </div></content></entry>
  1709.  
  1710. <entry>
  1711. <title>Parable of the Sofa</title>
  1712. <link href='https://www.tbray.org/ongoing/When/202x/2024/06/01/Parable-of-the-Sofa' />
  1713. <link rel='replies'        thr:count='8'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/06/01/Parable-of-the-Sofa#comments' />
  1714. <id>https://www.tbray.org/ongoing/When/202x/2024/06/01/Parable-of-the-Sofa</id>
  1715. <published>2024-06-01T12:00:00-07:00</published>
  1716. <updated>2024-06-02T08:47:35-07:00</updated>
  1717. <category scheme='https://www.tbray.org/ongoing/What/' term='The World/Economics' />
  1718. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  1719. <category scheme='https://www.tbray.org/ongoing/What/' term='Economics' />
  1720. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>When Lauren was pregnant with a child who’s now turning 25, we purchased a comfy dark-brown     leather sofa which fits our living room nicely.       What with kids and relatives and     employees and cats and Standards Comittees and friends and book clubs and socials, the butt-support cushions had, a quarter     century later, worn out. So we had them replaced, at a fair price, by a small local business. Which is something that modern     capitalism is trying to make impossible</div></summary>
  1721. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1722.    <p>When Lauren was pregnant with a child who’s now turning 25, we purchased a comfy dark-brown
  1723.    leather sofa which fits our living room nicely.  
  1724.    What with kids and relatives and
  1725.    employees and cats and Standards Comittees and friends and book clubs and socials, the butt-support cushions had, a quarter
  1726.    century later, worn out. So we had them replaced, at a fair price, by a small local business. Which is something that modern
  1727.    capitalism is trying to make impossible.</p>
  1728.    <img src="https://www.tbray.org/ongoing/When/202x/2024/06/01/worn.png" alt="Worn leather with a phone for scale" class="inline" />
  1729.    <p>I’ll be honest; when we realized how ratty the sofa was getting, my first thought was “crap, gonna have to buy a sofa”. But
  1730.    Lauren said “No, because new sofas are junk. Also, Luxcious.”</p>
  1731.    <p>I’ll get to Luxcious in a bit, but it turns out that new sofas, by and large, really are. Why would that be? Well, check out
  1732.    <a href="https://www.dwell.com/article/dtc-sofa-crisis-32304b9e">Why Are (Most) Sofas So Bad?</a> in <cite>Dwell</cite>
  1733.    magazine which has a weirdly-intermittent paywall, here’s <a href="https://archive.is/deGMX">another version</a>.</p>
  1734.    <p>From early in the piece: “Sofas made in the past 15 years or so are absolute garbage, constructed of
  1735.    sawdust compressed and bonded with cheap glue, simple brackets in place of proper joinery, substandard spring design, flimsy
  1736.    foam, and a lot of staples.” It’s excellent, well-written, and will take you some surprising places.</p>
  1737.    <p>But the subtext is
  1738.    drearily familiar. Globalization: Check. Cheap-labor arbitrage: Check. Tax engineering: Check. High profits:
  1739.    Check. Flat-packing: Check. Late Capitalism: Check check fucking check.</p>
  1740.    <p>But, quality furniture is expensive to make, and
  1741.    should be, but doesn’t wear out fast, thus deserves extended maintenance.</p>
  1742.    <h2 id='p-1'>Luxcious</h2>
  1743.    <p>Its
  1744.    <a href="https://luxciousupholstery.ca">Web site</a> (“Breathe new life into old furniture”) is way prettier than its location,
  1745.    in an old and extremely miscellaneous high-traffic zone: auto-body shops, hipster lounges, self-storage, beauty supplies…</p>
  1746.    <img src="https://www.tbray.org/ongoing/When/202x/2024/06/01/PXL_20240528_195945287.png" alt="Luxcious on Main Street" />
  1747.    <p>They’re family-run and idiosyncratic. You have to know how to find the sketchy rear parking lot and walk in the back
  1748.    door. But they’re friendly and competent. Here’s the new leather they bought for the cushions.</p>
  1749.    <img src="https://www.tbray.org/ongoing/When/202x/2024/06/01/PXL_20240522_202346949.png" alt="One cow’s worth of leather" />
  1750.    <p>And here’s the sofa with the re-covered cushions in place.</p>
  1751.    <img src="https://www.tbray.org/ongoing/When/202x/2024/06/01/PXL_20240528_204400696.png" alt="Sofa with refinished cushions" />
  1752.    <p>Yes, from this angle, the new cushions make the sofa’s back look shabby, but it’s not as obvious to the naked eye and after a
  1753.    decade or so we’ll never notice it.</p>
  1754.    <p>The whole job cost us $1100 Canadian.
  1755.    Given that the sofa cost three-thousand-plus 1999 dollars and new leather sofas of the “not flat-packed sawdust and
  1756.    glue” variety quickly get into five figures, the choice was a no-brainer.</p>
  1757.    <h2 id='p-2'>“Lifestyle”</h2>
  1758.    <p>This kind of transaction is exactly what modern capitalism is trying to stamp out.</p>
  1759.    <p>A single-location family-owned business that provides a living for a few people? With no plans to load up on debt or
  1760.    other financial
  1761.    engineering? Or for growth into unicorn status? No GenAI dimension? No marketing or public-relations people?</p>
  1762.    <p>In conversation with venture capitalists, you hear the phrase “lifestyle business”, meaning one that is doing nicely
  1763.    and rewarding the people who run it and which isn’t planning for unbounded growth.  The words “lifestyle business” are always, of
  1764.    course, uttered in a voice dripping with contempt. Luxcious is a lifestyle business.</p>
  1765.    <p>It seems blindingly obvious that an economy with a higher proportion of lifestyle businesses is going to be more resilient,
  1766.    more humane, and immensely more pleasant than the one that the Leaders Of Industry are trying to build.</p>
  1767.    <p>How would we get there from here?  I’m not smart enough to figure out what the regulatory regime is that would ban most of what
  1768.    private-equity does and tilt the playing field in favor of resilient lifestyle businesses.</p>
  1769.    <p>But I’d sure vote for a political party that convinced me it was trying to achieve that.</p>    
  1770. </div></content></entry>
  1771.  
  1772. <entry>
  1773. <title>Tedeschi Trucks</title>
  1774. <link href='https://www.tbray.org/ongoing/When/202x/2024/05/26/TTB' />
  1775. <link rel='replies'        thr:count='5'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/05/26/TTB#comments' />
  1776. <id>https://www.tbray.org/ongoing/When/202x/2024/05/26/TTB</id>
  1777. <published>2024-05-26T12:00:00-07:00</published>
  1778. <updated>2024-05-26T12:00:00-07:00</updated>
  1779. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts/Music' />
  1780. <category scheme='https://www.tbray.org/ongoing/What/' term='Arts' />
  1781. <category scheme='https://www.tbray.org/ongoing/What/' term='Music' />
  1782. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology/Audio' />
  1783. <category scheme='https://www.tbray.org/ongoing/What/' term='Technology' />
  1784. <category scheme='https://www.tbray.org/ongoing/What/' term='Audio' />
  1785. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Saturday night we went a concert by the     <a href='https://www.tedeschitrucksband.com'>Tedeschi Trucks Band</a> (TTB).  It was excellent and this is partly a review,     but mostly a challenge to the community of touring musicians: “Why aren’t your production     values as good as TTB’s?”</div></summary>
  1786. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1787.    <p>Saturday night we went a concert by the
  1788.    <a href="https://www.tedeschitrucksband.com">Tedeschi Trucks Band</a> (TTB).  It was excellent and this is partly a review,
  1789.    but mostly a challenge to the community of touring musicians: “Why aren’t your production
  1790.    values as good as TTB’s?”</p>
  1791.    <h2 id='p-1'>Just the Facts</h2>
  1792.    <p>TTB lives squarely in the middle of the Southern Rock genre, as invented by the Allman Brothers in 1970 or so.  Derek Trucks
  1793.    is the nephew of the Allmans’ original drummer     Butch Trucks and performed in a later iteration of that band.
  1794.    Susan Tedeschi had a successful career as a touring and recording blueswoman. Then she and Derek got married and merged their
  1795.    acts.</p>
  1796.    <img src="https://www.tbray.org/ongoing/When/202x/2024/05/26/PXL_20240526_041330763.png" alt="Tedeschi Trucks Band in concert in Vancouver in 2024" />
  1797.    <p>It’s a twelve-piece band: Susan and Derek on guitar, three backup vocalists, three horns,
  1798.    keyboards, bass, and two drummers (one white, one black, per the Southern-Rock canon).   The music is blues and soul, wandering into
  1799.    rock. Some of the songs are their own, others genre chestnuts (<cite>Statesboro Blues</cite>, <cite>High Time We
  1800.    Went</cite>). They played a three-hour show, but with not that many songs, because every tune features extended
  1801.    instrumental sections. All twelve members got a chance to shine, Derek had a break on every song, and Susan on quite a few.</p>
  1802.    <h2 id='p-2'>What was great</h2>
  1803.    <p>Only a couple of the songs weren’t memorable; they write well and cover only the best chestnuts. The musicianship was
  1804.    stellar, with electric guitar front and center. Derek is fluid and effortless, with beautiful tone; Susan solos less but
  1805.    actually plays more interesting stuff. Susan’s the lead voice but four other members are singers, they all got a featured
  1806.    spot and were all pretty great. Susan doesn’t have the vocal range or the shriek, but she had the most soul.</p>
  1807.    <p>What was best, though<span class='dashes'> —</span> out into “fucking awesome” territory<span class='dashes'> —</span> was what
  1808.    classical musicians call “ensemble” and I guess I’d call “band musicianship”. The songs’ arrangements are just razor-sharp,
  1809.    full of shifts and and breaks and little moments of drama and grace, intros and outros and bridges. The players were effortlessly
  1810.    locked onto the center of the rhythm, “so tight they were loose” as the saying goes. The amount of practicing this takes must be
  1811.    epic.</p>
  1812.    <p>Which was brilliantly supported by the sound people. Every instrument and voice was distinct and clear, and the dynamic
  1813.    range was maybe the best I’ve ever heard from an electric-guitar-based band. Every moment was multilayered and you could hear
  1814.    all the layers.</p>
  1815.    <p>You could tell (well, if you know something about
  1816.    concert sound, you could) that, at the soundboard, they were intervening judiciously, for example cranking the horns (or backup
  1817.    singers) and fading the guitars when that’s what the song needed.</p>
  1818.    <p>It was an audience that was fun to be part of, enthusiastically cheering all the solos and regularly leaping to their feet
  1819.    when a song hit the big up-curve. Especially impressive given that plenty of the crowd was old enough to have been there for the
  1820.    birth of Southern Rock.</p>
  1821.    <p>On top of which, the lighting was subtle and dramatic and tasteful, and only once in the whole three-hour show did they
  1822.    hurt my brain by obnoxiously flashing brilliant lights in my eyes.</p>
  1823.    <p>Thus my challenge:</p>
  1824.    <h2 id='p-3'>To every touring band: Be like TTB!</h2>
  1825.    <p>Seriously; My time on earth covers most of the history of live electric-music performance, plus I’m an audiophile, and for most of
  1826.    my life, most of the sound has been shitty.  But in the last few years I’ve
  1827.    regularly heard sound that was better than acceptable, and occasionally dazzlingly-good. But TTB is the most impressive
  1828.    combination I’ve heard of big ensemble, plenty of electric guitar, and sparkling sound.</p>
  1829.    <p>There is sort of an excuse: Rock, historically, has been carefully engineered to sound good on car radios; specifically
  1830.    the kind of car radios owned by impecunious youth. Dynamic range and layering are not features of this landscape.</p>
  1831.    <p>Anyhow, my exposure to TTB, prior to this, has been mostly YouTube, and I’ve enjoyed them, but I dunno, now that I’ve heard
  1832.    the real thing, I suspect the online version will feel thin.</p>
  1833.    <p>If TTB can do it, any band can. But plenty still don’t. That’s increasingly just not acceptable. I wonder if things will
  1834.    start to get generally better? Because I’m pretty sure the musicians care.</p>
  1835.    <h2 id='p-4'>Other observations</h2>
  1836.    <p>Running a 12-piece operation must be freaking expensive. I would <em>love</em> to hear the details of the economics. Saturday
  1837.    night they filled a 2600-seat hall with an average ticket price around C$120. So that’s over C$300K gross. The hall
  1838.    <a href="https://vancouvercivictheatres.com/media/9106/commercial-rental-rates-2024-25.pdf">costs C$21K</a> and then there’s
  1839.    Ticketmaster’s cut, which if the claims of the
  1840.    <a href="https://www.cbc.ca/news/entertainment/doj-sues-live-nation-1.7212432">recent DOJ litigation</a> are to be believed,
  1841.    would be egregious.</p>
  1842.    <p>I wonder how a TTB song gets built? In particular, who does the arrangements? Whoever it is, I’m a fan.</p>
  1843.    <p>Lauren and I were masked (N95) and looking across the audience as far as we could see revealed one other masked person. I
  1844.    dunno, 2600 people in an enclosed space. Call me crazy, but… no, call them crazy. I’m serious.</p>
  1845.    <p>Unusually, there were huge line-ups for the men’s washrooms, almost none for the women’s. The lady in the row behind us
  1846.    cackled and said “boomer prostates.”</p>
  1847. </div></content></entry>
  1848.  
  1849. <entry>
  1850. <title>The Colors of Racism</title>
  1851. <link href='https://www.tbray.org/ongoing/When/202x/2024/05/17/Colors-of-Racism' />
  1852. <link rel='replies'        thr:count='2'        type='application/xhtml+xml'        href='/ongoing/When/202x/2024/05/17/Colors-of-Racism#comments' />
  1853. <id>https://www.tbray.org/ongoing/When/202x/2024/05/17/Colors-of-Racism</id>
  1854. <published>2024-05-17T12:00:00-07:00</published>
  1855. <updated>2024-05-25T14:36:42-07:00</updated>
  1856. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  1857. <category scheme='https://www.tbray.org/ongoing/What/' term='The World' />
  1858. <summary type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Recently, somewhat by accident, I stumbled into reading a couple of monstrously racist texts, and I’m going to need to update     the Wikipedia entry for a famous British author. But I learned     a few things along the way that I want to share</div></summary>
  1859. <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
  1860.    <p>Recently, somewhat by accident, I stumbled into reading a couple of monstrously racist texts, and I’m going to need to update
  1861.    the Wikipedia entry for a famous British author. But I learned
  1862.    a few things along the way that I want to share.</p>
  1863.    <h2 id='p-5'>Disclosure</h2>
  1864.    <p>I try to be antiracist, but I don’t think I’m particularly good at it. I sometimes have bigoted feelings but try hard to
  1865.    recognize and not act on them. I’m convinced that humans are naturally tribal and antiracist work will continue to be required
  1866.    for the foreseeable future.</p>
  1867.    <h2 id='p-1'>The Author</h2>
  1868.    <p><a href="https://en.wikipedia.org/wiki/Anthony_Trollope">Anthony Trollope</a> (1815-1882) wrote 47 novels. I generally like
  1869.    them and we own a whole shelf-full. They are funny and tender and cynical; his characters love and marry and go into
  1870.    business and get elected to Parliament and are corrupt and engage in furious professional conflict. Those characters are,
  1871.    without exception, “gentle”, by which I mean members of the British ruling class.</p>
  1872.    <img src="https://www.tbray.org/ongoing/When/202x/2024/05/17/Trollope.png" alt="Anthony Trollope in 1864" />
  1873.    <div class='caption'><p>Anthony Trollope in 1864.</p></div>
  1874.    <p>When I was traveling around the world a lot, regularly crossing major oceans before the era of in-air Internet, Trollope was
  1875.    a regular companion; his books tend to be big and thick and extremely readable.  Want to get started?
  1876.    <cite>Barchester Towers</cite>, about a bitter feud among the clergymen of an English country town, is one of the funniest books
  1877.    ever written; also there’s an
  1878.    <a href="https://en.wikipedia.org/wiki/The_Barchester_Chronicles">excellent BBC adaptation</a>, with Alan Rickman
  1879.    deliciously smarmy as the horrid Mr Slope.</p>
  1880.    <h2 id='p-2'>What happened was…</h2>
  1881.    <p>I’m on a publishing-oriented mailing list and someone wrote “I stumbled on the fact that Trollope
  1882.    wrote a book that describes race relations in the British West Indies” and someone wrote back “It’s a travelogue not a novel,
  1883.    it’s called <cite>The West Indies and the Spanish Main</cite>, and be careful, that race-relations stuff may not be pleasant to
  1884.    read.”  On a whim, I summoned up the book from our excellent public-library system and, oh my goodness gracious, that “not
  1885.    pleasant” was understating it.</p>
  1886.    <h2 id='p-3'>The book</h2>
  1887.    <p>Trollope earned his living, while he was establishing his literary career, as an official of the British Post Office, rising to
  1888.    a high level in the organization and not leaving it until he was almost 50.</p>
  1889.    <p>In 1859, he was sent to
  1890.    reorganize the Post Office arrangements in the West Indies and the “Spanish Main”, the latter meaning southern Central America and
  1891.    northern South America. The expedition lasted several months and yielded this book.
  1892.    In his autobiography, Trollope wrote that he thought it “the best book which has come from my pen.”  I think history
  1893.    would disagree. It’s on the Internet Archive, but I’m not linking to explicit racism.</p>
  1894.    <p>So why am I going to write about it?!  Because now, 165 years after this book, racism and its consequences remain a
  1895.    central focus of our cultural struggles. Understanding the forces we combat is kind of important.
  1896.    Also, I recently researched and wrote about the
  1897.    <a href="/ongoing/When/202x/2022/06/12/Demerara-Rebellion">Demerara Rebellion</a> (of the enslaved against their oppressors, in
  1898.    1823) so I have more context on Trollope’s observations than most.</p>
  1899.    <h2 id='p-4'>Background</h2>
  1900.    <p>Trollope’s tone is grumpy but good-humored. In the places he visits, he is
  1901.    generally contemptuous of the hotels, the food, the weather, and the local government.</p>
  1902.    <p>The main narrative starts in Jamaica. By way of background,
  1903.    slavery had been abolished in 1833, just 25 years before. Many of the sugar plantations that occupied most of
  1904.    Jamaica had collapsed. Thus this:</p>
  1905.    <blockquote>
  1906.      <p>By far the greater portion of the island is covered with wild wood and jungle… Through this, on an occasional favourable
  1907.      spot, and very frequently on the roadsides, one see the gardens or provision-grounds of the negroes…</p>
  1908.      <p>These provision-grounds are very picturesque. They are not filled, as a peasant’s garden in England or in Ireland is
  1909.      filled, with potatoes and cabbages, or other vegetables similarly uninteresting in their growth; but contain cocoa-trees,
  1910.      breadfruit-trees, oranges, mangoes, limes, plantains, jack frout, sour-sop, avocado pears, and a score of others, all of which
  1911.      are luxuriant trees, some of considerable size, and all of them of great beauty… In addition to this, they always have the
  1912.      yam, which is with the negro somewhat as the potato is with the Irishman; only that the Irishman has nothing else, whereas the
  1913.      negro generally has either fish or meat, and has also a score of other fruits beside the yam.</p>
  1914.    </blockquote>
  1915.    <p>We wouldn’t use that word any more to describe Black people, but it was thought courteous in Trollope’s day. He does
  1916.    deploy the N-word, albeit rarely, and clarifying that it was normally seen, even back then, as an insult.</p>
  1917.    <h2 id='p-6'>The bad stuff</h2>
  1918.    <p>It comes on fast. In the Jamaica chapter, the first few subheadings are: “Introduction”, “Town”, “Country”,
  1919.    “Black Men”, “Coloured Men”, and “White Men”.  That “Black Men” chapter begins with six or so pages of pure racist dogma
  1920.    about the supposed shortcomings of Black people. I will not enumerate them, and obviously none
  1921.    stand up to the cold light of scientific inquiry.</p>
  1922.    <p>But then it gets a little weird. Trollope notes that “The first desire of a man in a state of a civilization is for property…
  1923.    Without a desire for property, man could make no progress.” And he is harsh in his criticism of the Black population for
  1924.    declining to work long shifts on the sugar plantations in hopes of building up some capital and getting ahead.</p>
  1925.    <p>And yet Trollope is forced to acknowledge that his position is weak. He describes an episode of a Black laborer
  1926.    knocking off work early and being abused by an overseer, saying he’ll starve. The laborer replies “No massa; no
  1927.    starve now; God send plenty yam.” Trollope muses “And who can blame the black man? He is free to work or free to let it alone.”
  1928.    It is amusingly obvious that this is causing him extreme cognitive dissonance.</p>
  1929.    <p>And he seems shockingly oblivious to issues of labor economics. On another occasion it is a group of young women who are
  1930.    declining the hot nasty work in the cane fields:</p>
  1931.    <blockquote>
  1932.      <p>On the morning of my visit they were lying with their hoes beside them…
  1933.      The planter was with me, and they instantly attacked him. “No, massa; we no workey; money no nuff,” said one. “Four bits
  1934.      no pay! no pay at all!” said another. “Five bits, massa, and we gin morrow ’arly.” It is hardly necessary to say that the
  1935.      gentleman refused to bargain with them… “But will they not look elsewhere for other work?” I asked. “Of course they will,” he
  1936.      said; “… but others cannot pay better than I do.”</p>
  1937.    </blockquote>
  1938.    <p>(A “bit” was one eighth of a dollar; I can remember my grandfather referring to a quarter, i.e. a 25¢ coin,
  1939.    as “two bits”.)</p>
  1940.    <p>They’re demanding a 20% raise and, as is very common today, the employer deems that impossible.</p>
  1941.    <p>Trollope contrasts the situation in Barbados, where there is no spare land and thus no “provision grounds” and the working
  1942.    class (in this case, all-Black) is forced to labor diligently for their daily bread; and is confident that this is better.</p>
  1943.    <p>He
  1944.    also visits Cuba, where slavery is still legal, and visits a plantation with an enslaved workforce: “During the crop time … from
  1945.    November till May, the negroes sleep during six hours out of the twenty-four, have two for their meals, and work for sixteen! No
  1946.    difference is made on Sunday.”  Trollope’s biggest concern was that the enslaved received no religious instruction nor
  1947.    opportunities to worship.</p>
  1948.    <p>Trollope regularly also has to wrestle with the tension that arises when he meets an accomplished or wise or influential Black
  1949.    person. For example, upon arriving in
  1950.    <a href="https://en.wikipedia.org/wiki/New_Amsterdam,_Guyana">New Amsterdam</a> (in Demerara):</p>
  1951.    <blockquote>
  1952.      <p>At ten o’clock I found myself at
  1953.      the hotel, and pronounce it to be, without hesitation, the best inn, not only in that colony, but in any of these Western
  1954.      colonies belonging to Great Britain. It is kept by a negro, one Mr. Paris Brittain, of whom I was informed that he was once a
  1955.      slave… he is merely the exception which proves the rule.</p>
  1956.    </blockquote>
  1957.    <p>Here are two more samples of Trollope twisting himself in knots over what seems to him an economic mystery.</p>
  1958.    <blockquote>
  1959.      <p>But if the unfortunate labourers could be made to work, say four days a week, and on an average eight hours a day, would
  1960.      not that in itself be an advantage ? In our happy England, men are not slaves ; but the competition of the labour market
  1961.      forces upon them long days of continual labour. In our own country, ten hours of toil, repeated six days a week, for the
  1962.      majority of us will barely produce the necessaries of life. It is quite right that we should love the negroes ; but I cannot
  1963.      understand that we ought to love them better than ourselves.</p>
  1964.    </blockquote>
  1965.    <blockquote>
  1966.      <p>The complaint generally resolves itself to this, that free labour in Jamaica cannot be commanded; that it cannot
  1967.      be had always, and up to a certain given quantity at a certain moment ; that labour is scarce, and therefore high priced, and
  1968.      that labour being high priced, a negro can live on half a day's wages, and will not therefore work the whole day — will not
  1969.      always work any part of the day at all, seeing that his yams, his breadfruit, and his plantains are ready to his
  1970.      hands. </p>
  1971.    </blockquote>
  1972.    <p>In what sense is England “happy”? Granted, it’s obvious from the point of view of the “gentle” ruling class, none of whom are
  1973.    doing manual labour sixty hours per week.</p>
  1974.    <p>That aside, the question he raises still stands, two centuries later: Why should anyone work harder than they need to, when
  1975.    the benefits of that work go to someone else?</p>
  1976.    <h2 id='p-7'>“Coloured”</h2>
  1977.    <p>There’s lots more of this, but it’s worth saying that while Trollope was racist against Blacks, he was, oddly, not a white
  1978.    supremacist. He considers the all-white colonial ruling class to be pretty useless, no better than the Blacks he sneers
  1979.    at, and proclaims that the future belongs to the “coloured” (i.e. mixed-race) people. He backs this up with some weird “Race
  1980.    Science” that I won’t go into.</p>
  1981.    <h2 id='p-8'>Unforgivable</h2>
  1982.    <p>Trollope’s one episode of pure venom is directed at the already-dying-out Indigenous people of the region, pointing out
  1983.    with approval that one of the island territories had simply deported that whole population, and suggesting that “we get rid
  1984.    of them altogether.”  This seems not to be based on race but on the observation that they “more than once endeavoured to turn
  1985.    out their British masters”. Colonialism is right behind racism in the line-up of European bad behaviors.
  1986.    It may also be relevant that he apparently did not meet a single Indigenous West-Indian person.</p>
  1987.    <h2 id='p-9'>Meta-Trollope</h2>
  1988.    <p>I finished reading <cite>The West Indies and the Spanish Main</cite> because Trollope’s portrayals of what he saw were so
  1989.    vivid and I couldn’t help being interested.</p>
  1990.    <p>I had read Trollope’s autobiography and some more
  1991.    bits and pieces about him, and had encountered not a word to the effect that whatever his virtues and accomplishments, he was
  1992.    shockingly racist. So I checked a couple of biographies out of the local library and yep, hardly a mention. One author noted that
  1993.    <cite>The West Indies and the Spanish Main</cite> was out of tune with today’s opinions, but there was no serious discussion of
  1994.    the issue.  Wikipedia had nothing, and still doesn’t as I write this, but I plan to fix that.</p>
  1995.    <p>I dug a little harder here and there around the Internet and turned up nothing about anti-Black racism, but a cluster of
  1996.    pieces addressing antisemitism; see
  1997.    <a href="https://slantbooks.org/close-reading/essays/troubled-by-trollope/">Troubled by Trollope?</a> and
  1998.    <a href="https://www.tabletmag.com/sections/arts-letters/articles/anthony-trollope-bicentennial">Why Anthony Trollope Is the
  1999.    Most Jewish of the Great English Novelists</a>.
  2000.    There are a few Jews in Trollope’s novels, ranging from wholly-admirable heroes (and heroines) to revolting
  2001.    villains. So you might think he comes off reasonably well, were it not for casual splashes of antisemitic tropes; the usual crap
  2002.    I’m not going to repeat here.</p>
  2003.    <p>In case it’s not obvious, Trollope’s writings and opinions were strikingly self-inconsistent,
  2004.    often within the course of a few pages. Well, and so is racism itself.</p>
  2005.    <p>At that point in history there was an entire absence of intersectionalist discourse about racism being, you
  2006.    know, intrinsically bad, and there were many who engaged in it enthusiastically and sincerely while remaining in polite
  2007.    society.</p>
  2008.    <p>Trollope’s racism is undeniable, but then he (once again, inconsistently) sounds non-racist in theory. (However, he was
  2009.    gloomy about the attitudes of the white population.) Check this out:</p>
  2010.    <blockquote>
  2011.      <p>It seems to us natural that white men should hold ascendency over those who are black or coloured. Although we have
  2012.      emancipated our slaves, and done so much to abolish slavery elsewhere, nevertheless we regard the negro as born to be a
  2013.      servant.
  2014.      We do not realize it to ourselves that it is his right to share with us the high places of the world, and that it should be an
  2015.      affair of individual merit whether we wait on his beck or he on ours. We have never yet brought ourselves so to think, and
  2016.      probably never shall.</p>
  2017.    </blockquote>
  2018.    <p>That text feels remarkably modern to me. I am a little more optimistic than he is in his closing four words; some white
  2019.    people work hard at antiracism. But for a lot of white people, his take remains depressingly accurate.</p>
  2020.    <h2 id='p-10'>Degrees of racism?</h2>
  2021.    <p>I suspect that, if Trollope were with us today, his writings would probably be conventionally antiracist.
  2022.    His opinions were solidly in his era’s mainstream and I suspect he would find himself in ours, because he was really a pretty
  2023.    conventional and actually kind of boring person.</p>
  2024.    <p>With the single exception of those two sentences about the Indigenous people, he seems to exhibit no
  2025.    particular <em>emotional</em> bias against any ethnic group.</p>
  2026.    <p>Why, you might wonder, do I mention this? Therein lies a tale. In his autobiography, when he discusses <cite>The West Indies
  2027.    and the Spanish Main</cite>, he notes that it received a favorable review in <cite>The Times</cite> of London. I thought I’d
  2028.    like, for the sake of context, to read that. (Thanks to
  2029.    <a href="https://cosocial.ca/@wdenton">William Denton</a> for retrieving the page images.)</p>
  2030.    <p>I certainly didn’t enjoy reading <cite>The West Indies</cite> (unsigned) from early 1860 in <cite>The
  2031.    Times</cite>.
  2032.    It fills most of a broadsheet page, dozens of column-inches one after the other oozing vitriolic hate of
  2033.    Black people. I’m not going to even try to describe it any further; I felt literally nauseated in reading and didn’t make it
  2034.    through to the end.</p>
  2035.    <p>I suspect that if that <cite>Times</cite> writer were with us today, he’d be an unreconstructed alt-right dog-whistler, a good ole
  2036.    boy in a MAGA hat.</p>
  2037.    <p>Reading this crap made me feel a little less angry about Trollope, who generally liked
  2038.    people. Here’s what I think I learned: Racism comes in multiple flavors.
  2039.    There are some people (like Trollope) who are intersectionally bigoted in a sort of unthinking and
  2040.    incurious way, but not that emotionally bound to it. These are the people that need to hear the antiracist message, loudly and
  2041.    clearly, over and over. Because they might listen and learn.</p>
  2042.    <p>Then there are the others. In 1860, that <cite>Times</cite> reviewer. Today, the slave-state GOP MAGAs, the Israeli
  2043.    settler movement, Modi’s <i>Hindutva</i> hoodlums.  They genuinely hate The Other, down in their bellies. It’s how they define
  2044.    themselves. Talking to them is useless. They have to be defeated and removed from positions of power and influence. Then,
  2045.    thankfully, they can be ignored. Because listening to them is useless too.</p>
  2046. </div></content></entry>
  2047.  
  2048. </feed>
  2049.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid Atom 1.0" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=http%3A//www.tbray.org/ongoing/ongoing.atom

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda