<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Desert Moon</title><link>http://www.dmoonc.com/</link><description>This is the blog of Desert Moon Consulting, LLC.</description><atom:link href="http://www.dmoonc.com/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Tue, 21 Apr 2026 19:40:01 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Portugal 2025</title><link>http://www.dmoonc.com/posts/2026/04/portugal-2025/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;div&gt;&lt;p&gt;In April of 2025, Bobi and I traveled to Portugal to visit friends and see the country. These are my notes from the trip.&lt;/p&gt;
&lt;figure class="centered_image_box"&gt;
    &lt;img class="clickable bordered_image" src="http://www.dmoonc.com/images/2026/04/portugal-2025/at_the_beach_with_rick_and_laura.jpeg" alt="At the beach with Rick and Laura" title="At the beach with Rick and Laura" onclick="window.open(this.src.replace('.jpg', '.full.jpg'), '_photo');"&gt;
    &lt;figcaption&gt;At the beach with Rick and Laura&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href="http://www.dmoonc.com/posts/2026/04/portugal-2025/"&gt;Read more…&lt;/a&gt; (30 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>Portugal</category><category>travel</category><guid>http://www.dmoonc.com/posts/2026/04/portugal-2025/</guid><pubDate>Sun, 12 Apr 2026 21:56:45 GMT</pubDate></item><item><title>More Fundamental Interconnectedness</title><link>http://www.dmoonc.com/posts/2025/12/more-fundamental-interconnectedness/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@dabeaz/115814790888953465/embed" style="background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;"&gt; &lt;a href="https://mastodon.social/@dabeaz/115814790888953465" target="_blank" style="align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;"&gt; &lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewbox="0 0 79 75"&gt;&lt;path d="M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z" fill="currentColor"&gt;&lt;/path&gt;&lt;/svg&gt; &lt;div style="color: #787588; margin-top: 16px;"&gt;Post by @dabeaz@mastodon.social&lt;/div&gt; &lt;div style="font-weight: 500;"&gt;View on Mastodon&lt;/div&gt; &lt;/a&gt; &lt;/blockquote&gt;
&lt;script data-allowed-prefixes="https://mastodon.social/" async src="https://mastodon.social/embed.js"&gt;&lt;/script&gt;

&lt;p&gt;&lt;br&gt;
This is as cool as &lt;a href="http://www.dmoonc.com/posts/fundamental-interconnectedness/"&gt;that time on Twitter&lt;/a&gt; when former Russian Ambassador Michael McFaul asked Grady Booch (!) for recommendations on how to learn Python (!?) - and Mr. Booch tagged Guido van Rossum.&lt;/p&gt;</description><guid>http://www.dmoonc.com/posts/2025/12/more-fundamental-interconnectedness/</guid><pubDate>Thu, 01 Jan 2026 01:51:47 GMT</pubDate></item><item><title>EV Roadtrip Efficiency</title><link>http://www.dmoonc.com/posts/2025/05/ev-roadtrip-efficiency/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;div&gt;&lt;p&gt;&lt;a href="https://marimo.io"&gt;marimo&lt;/a&gt; makes for a pretty nice notebook environment. I've been using it to compare the energy efficiency of my Tesla Model 3 vs. the Volkswagen ID.4 that has replaced it.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dmoonc.com/posts/2025/05/ev-roadtrip-efficiency/"&gt;Read more…&lt;/a&gt; (1 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>duckdb</category><category>marimo</category><category>polars</category><guid>http://www.dmoonc.com/posts/2025/05/ev-roadtrip-efficiency/</guid><pubDate>Fri, 30 May 2025 21:14:15 GMT</pubDate></item><item><title>Fractional Indexing</title><link>http://www.dmoonc.com/posts/2024/07/fractional-indexing/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;div&gt;&lt;p&gt;A couple of years ago I built a macOS/iOS data logging app for personal use. When I started work on it, I considered using a bespoke server and &lt;a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type"&gt;CRDTs&lt;/a&gt; to maintain data consistency among instances of the app. It was fun to &lt;a href="https://appdecentral.com/posts-in-the-replicating-types-crdts-in-swift-series/"&gt;learn the basics&lt;/a&gt; of CRDTs and to build a few prototypes. But I'm lazy, so I ended up using CloudKit.&lt;/p&gt;
&lt;p&gt;Sometimes I come across a blog post that makes me wish I'd pursued the server + CRDT approach. Today the trigger was Bartosz Sypytkowski's &lt;a href="https://www.bartoszsypytkowski.com/non-interleaving-lseq/"&gt;Non-interleaving Linear Sequence (LSeq) CRDT&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dmoonc.com/posts/2024/07/fractional-indexing/"&gt;Read more…&lt;/a&gt; (1 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><guid>http://www.dmoonc.com/posts/2024/07/fractional-indexing/</guid><pubDate>Wed, 31 Jul 2024 14:58:33 GMT</pubDate></item><item><title>Custom validation messages w. Svelte</title><link>http://www.dmoonc.com/posts/2023/02/svelte-and-custom-input-validation-messages/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;h3&gt;Example.svelte&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ts"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;HTMLInputElement&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valueMissing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setCustomValidity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Please provide a date of birth.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"date"&lt;/span&gt;
  &lt;span class="na"&gt;bind:this&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{control}"&lt;/span&gt;
  &lt;span class="na"&gt;required&lt;/span&gt;
  &lt;span class="na"&gt;on:invalid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{validate}"&lt;/span&gt;
  &lt;span class="na"&gt;on:change&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{validate}"&lt;/span&gt;
  &lt;span class="na"&gt;on:input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{validate}"&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"A required input"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;required&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;after&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;vertical-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;top&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Result&lt;/h3&gt;
&lt;div style="margin: 2rem"&gt;
&lt;img srcset="/images/2023/02/sv_custom_input_val/custom_validation_msg.png 2x" style="border: 1px solid #ccc; border-radius: 0.25rem;"&gt;
&lt;/div&gt;</description><category>Software Development</category><category>Svelte</category><category>Web Development</category><guid>http://www.dmoonc.com/posts/2023/02/svelte-and-custom-input-validation-messages/</guid><pubDate>Mon, 13 Feb 2023 18:16:21 GMT</pubDate></item><item><title>SvelteKit Session Management</title><link>http://www.dmoonc.com/posts/2023/02/sveltekit-session-management/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;div&gt;&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Manage session cookies using &lt;code&gt;hooks.server.ts&lt;/code&gt;, the &lt;code&gt;handle&lt;/code&gt; function, &lt;code&gt;event.locals&lt;/code&gt; and &lt;code&gt;app.d.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dmoonc.com/posts/2023/02/sveltekit-session-management/"&gt;Read more…&lt;/a&gt; (2 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>Software Development</category><category>SvelteKit</category><category>Typescript</category><category>Web Development</category><guid>http://www.dmoonc.com/posts/2023/02/sveltekit-session-management/</guid><pubDate>Sat, 11 Feb 2023 16:04:38 GMT</pubDate></item><item><title>Testing SwiftUI Tables</title><link>http://www.dmoonc.com/posts/2023/01/testing-swiftui-tables/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;p&gt;I maintain a macOS SwiftUI app whose user interface contains a Table, one with a bound sortOrder.&lt;/p&gt;
&lt;p&gt;The app's Xcode project contains UI tests that exercise the sorting logic, by clicking on the column headers. These tests are really fragile. Odds are good that any new release of macOS, or Xcode, or SwiftUI, will break them.&lt;/p&gt;
&lt;p&gt;I'm not sure why they're so fragile. I suspect the way SwiftUI generates the underlying view hierarchy for a Table may still be in flux.&lt;/p&gt;
&lt;p&gt;In any case, here is what I'm currently using to click on the column headers of a SwiftUI Table. This is for macOS 13.1, Xcode 14.2, Swift 5.7, SwiftUI 4.2.11.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;clickTableColumnHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableEl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XCUIElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tableEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tableColumns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allElementsBoundByIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Assume the column header lies above the column.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;CGVector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;coords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;coordinate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;withNormalizedOffset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Click twice to exercise both sort orders.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><category>macOS</category><category>Software Development</category><category>Swift</category><category>SwiftUI</category><category>Xcode</category><guid>http://www.dmoonc.com/posts/2023/01/testing-swiftui-tables/</guid><pubDate>Mon, 09 Jan 2023 14:09:00 GMT</pubDate></item><item><title>Svelte's Take on ObservableObject</title><link>http://www.dmoonc.com/posts/2022/12/sveltes-take-on-swiftuis-observableobject/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;div&gt;&lt;p&gt;SwiftUI's &lt;a href="https://developer.apple.com/documentation/combine/observableobject"&gt;ObservableObject and @Published&lt;/a&gt; make it easy to group related properties into a single class, and to react to changes of individual properties.&lt;/p&gt;
&lt;p&gt;I recently complained to my friend, Bobi, that &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; seemed lacking in this regard.  &lt;a href="https://svelte.dev/tutorial/reactive-assignments"&gt;Its tutorials&lt;/a&gt; always show components whose exportable state is defined by separate, top-level variable declarations.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'count is dangerously high!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;She set me straight: if you want to group related, observable properties, just use a writable store whose value is an Object (or if you prefer, a class instance).  Whenever any property is changed, interested parties react automatically.  &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dmoonc.com/posts/2022/12/sveltes-take-on-swiftuis-observableobject/"&gt;Read more…&lt;/a&gt; (1 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>Reactive</category><category>Software Development</category><category>Svelte</category><category>Swift</category><category>SwiftUI</category><guid>http://www.dmoonc.com/posts/2022/12/sveltes-take-on-swiftuis-observableobject/</guid><pubDate>Mon, 05 Dec 2022 13:33:06 GMT</pubDate></item><item><title>WINGS Cigarette Cards</title><link>http://www.dmoonc.com/posts/2022/11/wings-cigarette-cards/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;div&gt;&lt;div class="centered_image_box"&gt;
  &lt;img class="bordered_image" style="width: 70%; max-width: 512px" src="http://www.dmoonc.com/images/2022/11/wings_cigarette_cards.jpg" alt="WINGS Cigarette Cards Gallery" title="WINDS Cigarette Cards Gallery"&gt;&lt;br&gt;
  &lt;a href="https://misc.dmoonc.com/wings_cigarette_cards/index.html"&gt;WINGS Cigarette Cards&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="http://www.dmoonc.com/posts/2022/11/wings-cigarette-cards/"&gt;Read more…&lt;/a&gt; (1 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>Aviation</category><category>History</category><guid>http://www.dmoonc.com/posts/2022/11/wings-cigarette-cards/</guid><pubDate>Mon, 14 Nov 2022 16:46:34 GMT</pubDate></item><item><title>macOS, Xcode, Ventura: When CloudKit Stops Syncing</title><link>http://www.dmoonc.com/posts/2022/11/macos-ventura-when-cloudkit-stops-syncing/</link><dc:creator>Mitch Chapman</dc:creator><description>&lt;div&gt;&lt;p&gt;(This is for future reference, when this sort of problem arises again.)&lt;/p&gt;
&lt;p&gt;Last spring I started working on a pair (macOS, iOS) of personal utility applications.  They relied on CloudKit storage.  For months they worked well together.  Then, as soon as I updated to macOS 13 Ventura, they stopped syncing.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dmoonc.com/posts/2022/11/macos-ventura-when-cloudkit-stops-syncing/"&gt;Read more…&lt;/a&gt; (1 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>CloudKit</category><category>Core Data</category><category>Mac</category><category>macOS</category><category>Software Development</category><category>Xcode</category><guid>http://www.dmoonc.com/posts/2022/11/macos-ventura-when-cloudkit-stops-syncing/</guid><pubDate>Tue, 08 Nov 2022 19:43:01 GMT</pubDate></item></channel></rss>