<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Les Orchard is typing&#8230;</title>
	<atom:link href="/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Trying WordPress again</description>
	<lastBuildDate>Wed, 23 Jan 2019 18:02:11 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.0.3</generator>

<image>
	<url>/wp-content/uploads/2018/09/me-55aBIc25-150x150.jpg</url>
	<title>Les Orchard is typing&#8230;</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>A river, not an inbox</title>
		<link>/2019/01/23/a-river-not-an-inbox/</link>
		<pubDate>Wed, 23 Jan 2019 18:00:55 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[feeds]]></category>
		<category><![CDATA[glitch]]></category>
		<category><![CDATA[metablogging]]></category>
		<category><![CDATA[rss]]></category>

		<guid isPermaLink="false">/?p=402</guid>
		<description><![CDATA[Feed readers work best for me when they're rivers, not inboxes.]]></description>
				<content:encoded><![CDATA[
<p>I&#8217;ve been tinkering with RSS feeds since roughly the year 2000. I&#8217;ve published lots of feeds and I&#8217;ve used lots of feed readers. I&#8217;ve also written a bunch of feed readers &#8211; mainly for my own private use, because I haven&#8217;t wanted to trouble anyone else with my shameful UX and garbage code. (I <em>did</em> <a href="https://www.amazon.com/dp/0764597582/ref=cm_sw_r_tw_dp_U_x_pCksCbP7DVM9N">write a book using some of that stuff</a>, so I guess I didn&#8217;t keep it <em>all</em> private.)</p>



<p>Apropos of that, I&#8217;ve started writing <a href="https://glitch.com/~lmo-feeder">another feed reader</a>. This time I am sharing, insofar as <a href="https://glitch.com/~lmo-feeder">you can go play with it on Glitch</a> and remix if tinkering with it strikes your fancy.</p>



<figure class="wp-block-image"><img src="/wp-content/uploads/2019/01/Capture-1024x628.png" alt="" class="wp-image-404" srcset="/wp-content/uploads/2019/01/Capture-1024x628.png 1024w, /wp-content/uploads/2019/01/Capture-300x184.png 300w, /wp-content/uploads/2019/01/Capture-768x471.png 768w, /wp-content/uploads/2019/01/Capture-620x380.png 620w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>In fact, you <em>have</em> to remix it, if you&#8217;d like it to use your own set of feed subscriptions. The web interface is read-only and all the data management happens at the command line. Very lazy, very <a href="https://www.youtube.com/watch?v=KEkrWRHCDQU">Hackerman</a>, but it scratches my own itch so far.</p>



<p>Here&#8217;s the thing I&#8217;m remembering: Feed readers work best for me when they&#8217;re rivers, not inboxes. Dave Winer <a href="http://scripting.com/2014/06/02/whatIsARiverOfNewsAggregator.html">has been writing about Rivers of News</a> for years. My interpretation goes like so:</p>



<ul><li>No read / unread flags. There is no &#8220;<a href="http://randsinrepose.com/archives/the-one-about-information-consumption/">Select All, Mark as Read</a>&#8220;.</li><li>No queue to be processed. &#8220;<a href="http://inessential.com/2019/01/22/mark_all_as_read">Your RSS reader is not your task master.</a>&#8220;</li><li>Reverse chronological order everywhere &#8211; new stuff first.</li><li>Easy-to-skim capsules of content, grouped into relevance by feed.</li><li>Navigate by paddling down the river. Spacebar, page down, mouse wheel, finger drag &#8211; but, crucially, this isn&#8217;t item-by-item navigation.</li><li>Open new tabs in the background or push into Pocket whenever something looks worth reading.</li><li>Take occasional breaks to read tabs.</li><li>Continue on to the end of the river or until things look familiar.</li></ul>



<p>Before my new DIY effort, my last reader was <a href="https://tt-rss.org/">Tiny Tiny RSS</a>. It&#8217;s a good feed reader, not entirely unlike ye olde Google Reader. The thing that kept kind of driving me away from it is that it&#8217;s too inboxy. I mean, you don&#8217;t <em>have</em> to interact with it like that, but it invites that usage and that I&#8217;m tempted by it. It feels like work and I avoid it often.</p>



<p>Actually, even it&#8217;s not strictly a feed reader, Google Discover has been my most-used news stream over the past couple of years. I&#8217;d roll out of bed, swipe over to it from my phone&#8217;s home screen, thumb through it, and start loading up tabs. <a href="https://typing.lmorchard.com/2019/01/05/done-with-googles-feed/">I&#8217;m pretty much done with that thing now, though.</a></p>



<p>So, rough &amp; ugly as it is, I&#8217;m finding it a lot easier &amp; more enjoyable to paddle down my new river. I even got it working acceptably on my phone. I&#8217;ve been catching a lot more news than I have been in probably years. It&#8217;s not like this is my first River of News reader &#8211; it&#8217;s just that I seem to have forgotten how I used to read news from, like, ten years ago.</p>



<p>Here&#8217;s another weird thing: It re-occurred to me that Facebook and Twitter and Mastodon are all basically Rivers of News. I mean, quirky rivers with occasional algorithmic rapids &#8211; but still, they&#8217;re not inboxes. I say re-occurred, because I&#8217;ve had these thoughts before. Somehow I just forgot and have been trying to engage with feeds via an inbox again. I wonder why?</p>



<p>Anyway, this was in my head. Now it&#8217;s not. Hopefully I&#8217;ll do more of that here.</p>
]]></content:encoded>
			</item>
		<item>
		<title>Done with Google&#8217;s Feed</title>
		<link>/2019/01/05/done-with-googles-feed/</link>
		<pubDate>Sat, 05 Jan 2019 06:37:34 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[amp]]></category>
		<category><![CDATA[feeds]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[webdev]]></category>

		<guid isPermaLink="false">/?p=379</guid>
		<description><![CDATA[For the past year or so, I've been using Google's Discover feed from my phone's home screen for part of my daily news habit. It's been mostly okay and often relevant. But, little paper cuts have finally hit my annoyance threshold.]]></description>
				<content:encoded><![CDATA[
<p>For the past year or so, I&#8217;ve been using <a href="https://www.blog.google/products/search/introducing-google-discover/">Google&#8217;s Discover feed</a> from my phone&#8217;s home screen for part of my daily news habit. It&#8217;s been mostly okay and often relevant. </p>



<ul class="wp-block-gallery aligncenter columns-2 is-cropped"><li class="blocks-gallery-item"><figure><img src="/wp-content/uploads/2019/01/Screenshot_20190105-011324_Google-1-498x1024.jpg" alt="" data-id="393" data-link="/?attachment_id=393" class="wp-image-393" srcset="/wp-content/uploads/2019/01/Screenshot_20190105-011324_Google-1-498x1024.jpg 498w, /wp-content/uploads/2019/01/Screenshot_20190105-011324_Google-1-146x300.jpg 146w, /wp-content/uploads/2019/01/Screenshot_20190105-011324_Google-1-768x1579.jpg 768w, /wp-content/uploads/2019/01/Screenshot_20190105-011324_Google-1-620x1274.jpg 620w, /wp-content/uploads/2019/01/Screenshot_20190105-011324_Google-1.jpg 1440w" sizes="(max-width: 498px) 100vw, 498px" /><figcaption>So far, so good, but this news kind of stresses me out.<br></figcaption></figure></li><li class="blocks-gallery-item"><figure><img src="/wp-content/uploads/2019/01/Screenshot_20190105-011839_Google-1-498x1024.jpg" alt="" data-id="394" data-link="/?attachment_id=394" class="wp-image-394" srcset="/wp-content/uploads/2019/01/Screenshot_20190105-011839_Google-1-498x1024.jpg 498w, /wp-content/uploads/2019/01/Screenshot_20190105-011839_Google-1-146x300.jpg 146w, /wp-content/uploads/2019/01/Screenshot_20190105-011839_Google-1-768x1579.jpg 768w, /wp-content/uploads/2019/01/Screenshot_20190105-011839_Google-1-620x1274.jpg 620w, /wp-content/uploads/2019/01/Screenshot_20190105-011839_Google-1.jpg 1440w" sizes="(max-width: 498px) 100vw, 498px" /><figcaption> Yes, I am totally a sportsball fan. Also, check out that year-old book recommendation.</figcaption></figure></li></ul>



<p>But, little paper cuts have finally hit my annoyance threshold &#8211; in particular:</p>



<ol><li>Quite often, the feed offers items that are months or years old</li><li>Nearly every item links to a site using AMP</li><li>Nearly every site using AMP does it badly</li></ol>



<p>The first issue would be kind of forgivable, but I feel like a dummy every time I run into it without realizing it partway into an article. So, I guess, fool me once shame on you, fool me twice &#8211; you can&#8217;t get fooled again. Call me a curmudgeon, but I&#8217;m getting really worn out on non-chronological feed algorithms.</p>



<p>That second issue, though. As a web developer, I&#8217;ve been kind of grumbly about the general concept of AMP. But, as a user who reads news, Google&#8217;s AMP has felt like garbage.</p>



<p>It took me awhile to put it together, but things seemed weird about pages I visited from the Discover feed. I&#8217;m not sure if it was a recent decision for Google&#8217;s Discovery feed to link mostly to AMP content, but I&#8217;ve been noticing it more lately. And what I&#8217;ve noticed is what&#8217;s missing: Videos, tweets, comments, and other random bits of content.</p>



<p>Case in point:</p>



<figure class="wp-block-embed-twitter wp-block-embed is-type-rich is-provider-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="en" dir="ltr">What&#39;s great about Google&#39;s AMP is when news sites like <a href="https://twitter.com/HuffPost?ref_src=twsrc%5Etfw">@HuffPost</a> make effective use of it in stories largely consisting of twitter embeds and videos <a href="https://t.co/NhLqTPjFwe">pic.twitter.com/NhLqTPjFwe</a></p>&mdash; Les Orchard (@lmorchard) <a href="https://twitter.com/lmorchard/status/1067443276842745858?ref_src=twsrc%5Etfw">November 27, 2018</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p>Yes, that Tweet is mostly blank white space. It&#8217;s what a lot of articles published as AMP look like to me. It feels like no site publishing in AMP has made any effort to actually <em>use</em> AMP.</p>



<p>It just seems like they run their existing pages through a dumb filter and never observe the result. Page elements are just omitted, the content rarely (if ever) adapted to the format. Occasionally, a page will have partial text with a &#8220;Read full article&#8221; button &#8211; and a click of that button leads to a non-AMP page.</p>



<p>In fact, I can often just delete &#8220;<code>/amp</code>&#8221; or &#8220;<code>?amp</code>&#8221; from the URL &#8211; and like magic, all the missing content appears. It&#8217;s almost like the only incentive to use AMP is to check off a box for search rankings.</p>



<p>So anyway, in closing: <a href="https://twitter.com/lmorchard/status/1079894325868314624">I&#8217;ve been tinkering with my own feed reader again</a>. With a few CSS tweaks, it works on my phone. It&#8217;s been plenty relevant so far. Thus, I think I&#8217;m done with Google&#8217;s feed for now and will try to avoid AMP pages wherever possible as a user.</p>
]]></content:encoded>
			</item>
		<item>
		<title>I ❤️ Glitch</title>
		<link>/2018/12/30/i-heart-glitch/</link>
		<pubDate>Sun, 30 Dec 2018 23:24:29 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[glitch]]></category>
		<category><![CDATA[webdev]]></category>

		<guid isPermaLink="false">/?p=355</guid>
		<description><![CDATA[Lately, when I start tinkering with a side project, I reach for Glitch. ]]></description>
				<content:encoded><![CDATA[
<p>Lately, when I start tinkering with a side project, I reach for <a href="https://glitch.com/">Glitch</a>. </p>



<p>That sounds like the start of a toothpaste commercial, but bear with me. The thing about Glitch is it&#8217;s not very weird. The general vibe and decor of the place reminds me of <a href="https://blog.lmorchard.com/2018/03/01/sio2pi/#atari-was-my-first-love">my favorite BASIC programming books from the early 80s</a>. But, behind that is some dead boring technology.</p>



<figure class="wp-block-image"><img src="/wp-content/uploads/2018/12/image_0-1024x768.jpg" alt="" class="wp-image-365" srcset="/wp-content/uploads/2018/12/image_0-1024x768.jpg 1024w, /wp-content/uploads/2018/12/image_0-300x225.jpg 300w, /wp-content/uploads/2018/12/image_0-768x576.jpg 768w, /wp-content/uploads/2018/12/image_0-620x465.jpg 620w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Out front, there&#8217;s a no-frills web-based IDE &#8211; not as complex as something like <a href="https://aws.amazon.com/cloud9/">Cloud9</a>, but plenty powerful for most tinkerings. In back, there&#8217;s a tiny Linux machine with a sliver of RAM and a dollop of storage &#8211; not entirely unlike a Raspberry Pi. Along with basic editing, the IDE offers access to console log output and a web-based terminal where you can engage in command line shenanigans.</p>



<figure class="wp-block-image"><img src="/wp-content/uploads/2018/12/Capture.png" alt="" class="wp-image-367" srcset="/wp-content/uploads/2018/12/Capture.png 547w, /wp-content/uploads/2018/12/Capture-300x180.png 300w" sizes="(max-width: 547px) 100vw, 547px" /></figure>



<figure class="wp-block-image is-resized"><img src="/wp-content/uploads/2018/12/Capture-4.png" alt="" class="wp-image-374" width="547" height="313" srcset="/wp-content/uploads/2018/12/Capture-4.png 654w, /wp-content/uploads/2018/12/Capture-4-300x172.png 300w, /wp-content/uploads/2018/12/Capture-4-620x356.png 620w" sizes="(max-width: 547px) 100vw, 547px" /></figure>



<p>Every project gets its own <code>*.glitch.me</code> subdomain with an SSL-enabled web server all ready to go. And, though you <em>can </em>store assets like images and such alongside source code, there&#8217;s also a separate CDN that accepts uploads via drag and drop.</p>



<figure class="wp-block-image"><img src="/wp-content/uploads/2018/12/Capture-1.png" alt="" class="wp-image-368" srcset="/wp-content/uploads/2018/12/Capture-1.png 674w, /wp-content/uploads/2018/12/Capture-1-300x72.png 300w, /wp-content/uploads/2018/12/Capture-1-620x148.png 620w" sizes="(max-width: 674px) 100vw, 674px" /></figure>



<p>For version control, <a href="https://medium.com/glitch/reinventing-version-control-with-glitch-rewind-914c350da442">you get an easy-to-grok rewindable timeline</a>. The neat thing, though, is that this is backed by a git repository. Every ten minutes or so, the system commits your changes and you can roll back with a file-by-file preview of changes right in the editor.</p>



<div class="wp-block-image"><figure class="alignright is-resized"><img src="/wp-content/uploads/2018/12/Capture-2.png" alt="" class="wp-image-369" width="243" height="202"/><figcaption>Look at that beautiful repo URL</figcaption></figure></div>



<p>I <a href="https://twitter.com/lmorchard/status/1077279027759599616">recently discovered</a> that the Glitch API opened up direct access to the underlying git repository. So, with plain old git tools, you can back up or transfer your projects away from Glitch. You can even work through GitHub if that strikes your fancy. Ironically, these sorts of clearly marked exits make me more comfortable with sticking around.</p>



<p>I&#8217;ve read <a href="https://support.glitch.com/t/can-i-run-a-python-app-in-glitch/2140">that other languages work on Glitch</a>, but my main thing around there there is working with JavaScript in Node.js and the browser. The happy path is well-trodden: On edits, web pages auto-refresh and servers auto-restart. Tweaks to dependencies in <code>package.json</code> are automatically applied from a fast <a href="https://pnpm.js.org/">pnpm</a> cache. And, if you don&#8217;t quite like the auto-restarts, <a href="https://glitch.com/edit/#!/watch-json?path=README.md:1:0">you can customize with a </a><code><a href="https://glitch.com/edit/#!/watch-json?path=README.md:1:0">watch.json</a></code><a href="https://glitch.com/edit/#!/watch-json?path=README.md:1:0"> file</a>.</p>



<p>To circle back, it might sound like I accused Glitch of being boring like that&#8217;s a bad thing. But, I know that the infrastructure keeping things boring must be anything but. And the effort to support what&#8217;s common clears the way for more exciting things folks can do when they don&#8217;t have to focus on the setup and knob tweaking that so much of modern web development seems to require.</p>



<p>When I start a new bit of tinkering on Glitch, I don&#8217;t have to go through a boilerplate dance of <code>git init</code> and <code>npm init</code> and <code>npm install</code> and trying to remember what I did last time to configure Webpack and <em>yadda yadda yadda</em>. I just start a remix of one of the many starter projects on Glitch and commence tinkering. </p>



<div class="wp-block-image"><figure class="alignleft is-resized"><img src="/wp-content/uploads/2018/12/Capture-3.png" alt="" class="wp-image-370" width="229" height="196" srcset="/wp-content/uploads/2018/12/Capture-3.png 472w, /wp-content/uploads/2018/12/Capture-3-300x256.png 300w" sizes="(max-width: 229px) 100vw, 229px" /><figcaption>Listing projects on my home page<br><br></figcaption></figure></div>



<p>Then I can tweet or toot or do whatever to share with the <code>*.glitch.me</code> URL and show off what I&#8217;ve got so far. <a href="https://medium.com/glitch/making-learning-to-code-more-accessible-d802effd52bf">I can even embed my projects on my own pages</a>. In starting to explore the API, I added a list of recent projects to <a href="https://lmorchard.com/">my home page</a>. And if you want to play, it&#8217;s just a click or two to remix <em>my</em> work as your own.</p>



<p>And then, if or when I <em>do </em>want to get into some knob tweaking &#8211; Glitch gets out of the way. I can replace and configure the built-in auto-restarts and file watchers. I can run npm scripts from the command line for linting and formatting and whatever else I feel like doing. I can set up a fancy Webpack dev server complete with hot module replacement or whatever ends up being the latest hotness.</p>



<p>So, I guess to sum up: Glitch is pretty cool. I&#8217;m probably going to be using it a whole bunch in the near future.</p>
]]></content:encoded>
			</item>
		<item>
		<title>GOTO Hell</title>
		<link>/2018/10/10/goto-hell/</link>
		<pubDate>Wed, 10 Oct 2018 05:53:34 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[fiction]]></category>
		<category><![CDATA[horror]]></category>
		<category><![CDATA[spoopy]]></category>
		<category><![CDATA[stories]]></category>

		<guid isPermaLink="false">/?p=333</guid>
		<description><![CDATA[Here's a spoopy little story I wrote. The gist of it comes from a dream. There's blood, murder, an unhealthy relationship, and a bit of existential angst.]]></description>
				<content:encoded><![CDATA[
<p>Here&#8217;s a spoopy little story I wrote. The gist of it comes from a dream. There&#8217;s blood, murder, an unhealthy relationship, and a bit of existential angst.<br/></p>



<hr class="wp-block-separator"/>



<p><em>&#8220;Heaven &amp; Hell are real&#8221;, you said.</em></p>



<p>I think of this while I clean my knives. A body cools at my feet. Blood flows with the grade of the pavement to the nearest storm drain.</p>



<p><em>&#8220;Heaven &amp; Hell are real,&#8221; you said, &#8220;I pushed it all to production this afternoon.&#8221;</em></p>



<p>I don&#8217;t know who this was. It doesn&#8217;t matter. It&#8217;s not you.</p>



<p><em>&#8220;There&#8217;s this sequence where your soul gets weighed.&#8221;  You smirked, proud. &#8220;It&#8217;s really cool.&#8221;</em></p>



<p>The alley is just a glance away from passersby on the street. But, no one does.<br/></p>



<p><em>&#8220;A deep memory scan, criminal records, credit reports. Hell, even browser history. It all goes in.&#8221;</em></p>



<p>In a dive bar down the block, I leave another body in the grimy bathroom. I don&#8217;t make more of a mess than was already there.</p>



<p><em>&#8220;But&#8221;, you whispered (and I shuddered), &#8220;the rules are different for us.&#8221;</em></p>



<p>I push a dog walker into the river. The dog tags along with me until I hand the leash to a bewildered someone stepping off a bus.</p>



<p><em>&#8220;I slipped a bias into the algorithm&#8221;, you said, stroking my hair. &#8220;We&#8217;d have to be <strong>monsters</strong> not to make it in.&#8221;</em></p>



<p>On the bus, it&#8217;s a poisoning between stops. I slip a needle into a passed-out drunk.</p>



<p><em>&#8220;We&#8217;ll be together forever&#8221;, you sighed.</em></p>



<p>I drop a brick off a bridge: it smashes through the windshield of a passing auto-cab. I don&#8217;t think I hurt anyone &#8211; the cab looked empty.</p>



<p><em>&#8220;I never asked for that&#8221;, I said to no one. You were already asleep.</em></p>



<p>You died in a car wreck, last week. You were driving. Who even does that anymore?</p>



<p>The next day, I donated everything to charity. I did it in your name. Every bit counts while you&#8217;re still in the processing queue.</p>



<p>There&#8217;s still work ahead for me, though. I&#8217;ll kill everyone in this city if it means I&#8217;ll never see your face again.</p>
]]></content:encoded>
			</item>
		<item>
		<title>Generating a Firefox static theme from a web page</title>
		<link>/2018/10/05/generating-a-theme-add-on-for-firefox-from-a-web-page/</link>
		<pubDate>Fri, 05 Oct 2018 22:03:34 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[color]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[mozilla]]></category>

		<guid isPermaLink="false">/?p=180</guid>
		<description><![CDATA[Folks would like to export their themes from Firefox Color as standalone theme add-ons. These can be submitted to AMO and allow for further advanced tinkering not supported by the theme editor in Color. Up until today, I was thinking that we'd need to do this with server-side code like an AWS Lambda function. But, with more due diligence, I realized all the pieces exist to make this happen completely in the browser.]]></description>
				<content:encoded><![CDATA[
<p>Folks would like to export their themes from <a href="https://color.firefox.com/">Firefox Color</a> as standalone theme add-ons. These can be submitted to AMO and allow for further advanced tinkering not supported by the theme editor in Color.</p>



<p>Up until today, I was thinking that we&#8217;d need to do this with server-side code like an AWS Lambda function. But, with more due diligence, I realized all the pieces exist to make this happen completely in the browser.</p>



<hr class="wp-block-separator"/>



<p>Themes in Firefox have gone through many iterations and changes. But, for present purposes, consider <a href="https://blog.mozilla.org/addons/2018/09/20/future-themes-here/">the recent addition</a> of <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Themes/Theme_concepts#Static_themes">static themes</a>. A static theme is a <code>.zip</code> archive, containing <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json">a <code>manifest.json</code></a> with <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/theme">the properties of the theme</a>, accompanied by whatever images are used.</p>



<p>With that in mind, producing a static theme from the Color web app looks roughly like this:<br/></p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// store is Firefox Color's Redux store
const state = store.getState();

// selectors.theme() extracts the current theme from the store
const themeData = selectors.theme(state);

// convertToBrowserTheme translates our Redux data into a Firefox theme
const theme = convertToBrowserTheme(themeData);

// Find JSZip at http://stuk.github.io/jszip/
const zip = new JSZip();

// This is a very minimal manifest for a theme
const manifest = {
  manifest_version: 2,
  version: "1.0",
  name: "My New Theme",
  theme
};

// Add a pretty-printed JSON string as manifest.json to the zip
zip.file("manifest.json", JSON.stringify(manifest, null, "  "));

// Generate the .zip as a base64 and reformat it as a data: URI
return zip
  .generateAsync({ type: "base64" })
  .then(data => "data:application/x-xpinstall;base64," + data);</pre>



<p>Firefox Color uses <a href="https://github.com/mozilla/FirefoxColor/tree/master/src/preset-themes">its own internal representation of a theme</a> to make things easier to manage in the React / Redux code that drives our UI. But, when the theme <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-f5a2070aff5dd0481734315255ba709fR166">is applied to the browser by the Color add-on</a>, this representation is converted to <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/theme">the Theme schema</a> expected by <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Themes/Theme_concepts#Static_themes#Dynamic_themes">dynamic theme API</a> in Firefox.</p>



<p>Conveniently, this conversion code can be extracted &amp; generalized to produce the <code>theme</code> property of <code>manifest.json</code> in a static theme. <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-f76982c7edcdd7a4e58415e0407a1c33R192">That&#8217;s what <code>convertToBrowserTheme()</code> does</a>.<br/></p>



<p>From there, <a href="http://stuk.github.io/jszip/">Stuart Knightley&#8217;s JSZip module</a> forms the keystone of the whole thing. To create a <code>manifest.json</code> file in an archive, I just have to generate the contents as a string with <code>JSON.stringify()</code> and feed that into <code>zip.file()</code>. </p>



<p>Then, I can generate the <code>.zip</code> archive and encode it as a Base64 string. Again, this all works in a browser! With a small tweak, I can use that as <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs">a data: URL</a> in <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Attributes">a download link</a>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="html" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;a download="theme.xpi" href={exportedTheme}>theme.xpi&lt;/a></pre>



<p>Thanks to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download">the HTML5 download attribute</a>, clicking on this link in Firefox results in an Open / Save dialog to download the data:</p>



<figure class="wp-block-image"><img src="/wp-content/uploads/2018/10/Capture-1.png" alt="" class="wp-image-198" srcset="/wp-content/uploads/2018/10/Capture-1.png 643w, /wp-content/uploads/2018/10/Capture-1-300x223.png 300w, /wp-content/uploads/2018/10/Capture-1-620x462.png 620w" sizes="(max-width: 643px) 100vw, 643px" /></figure>



<hr class="wp-block-separator"/>



<p>Oh, but I mentioned images. That complicates things. In Firefox Color, there are two ways to get an image into your theme:</p>



<ol><li>Use one of the predefined background patterns &#8211; these are stored internally as file paths to images bundled with the Color add-on<br/></li><li>Import up to three images of your own &#8211; these are encoded as <code>data:</code> URLs from the imported image data<br/></li></ol>



<p>For producing a static theme, I need to convert each of these cases into both an image file in the archive and a file path in <code>manifest.json</code>. That leads me to two variations for handling image data:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">function addImage(zip, data) {
  if (data.startsWith("data:")) {
    // Convert data: URL into binary file entry in zip
    const [meta, b64data] = data.split(",", 2);
    const [type] = meta.substr(5).split(/;/, 1);
    const filename = `images/${genId()}${extensions[type]}`;
    zip.file(filename, base64ToUint8array(b64data));
    return filename;
  }

  if (data.startsWith("images/")) {
    // Convert file path into pending image fetch.
    const filename = data;
    pendingImages.push(
      fetch(filename)
        .then(response => response.blob())
        .then(data => zip.file(filename, data))
    );
    return filename;
  }
}</pre>



<p>For user-imported images, I have the data immediately available as data: URLs in the Redux store. After some hacky parsing of a data: URL, I can invent a unique filename and convert Base64 to binary before adding to the <code>.zip</code> archive. <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-e551cbd37d1de93c019232d073ec92aaR56">The <code>genId()</code> function</a> helps with the former, and <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-e551cbd37d1de93c019232d073ec92aaR94">the <code>base64ToUint8array()</code> function</a> helps with the latter. (I&#8217;m leaving out some details like these functions, but you can find them on GitHub.)<br/></p>



<p>The built-in images, though, are only represented as file paths in Redux. Luckily, these paths correspond directly to images deployed with the web site. So, I can use <code>fetch()</code> to grab these via HTTP and add each to the archive as binary blobs. This is an asynchronous operation &#8211; so I assemble a <code>pendingImages</code> array collecting Promises that need resolution before we&#8217;re done.</p>



<p>Putting it all together slightly complicates my earlier code sample:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="10-26,36" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const zip = new JSZip();
const state = store.getState();
const themeData = selectors.theme(state);
const customBackgrounds = selectors.themeCustomImages(state);

// bgImages and customBackgrounds are sources of image data
const theme =
  convertToBrowserTheme(themeData, bgImages, customBackgrounds);

reset();

if (theme.images) {
  const { images } = theme;
  const { additional_backgrounds } = images;
  if (images.headerURL) {
    images.headerURL = addImage(zip, images.headerURL);
  }
  if (additional_backgrounds) {
    for (let idx = 0; idx &lt; additional_backgrounds.length; idx++) {
      additional_backgrounds[idx] = addImage(
        zip,
        additional_backgrounds[idx]
      );
    }
  }
}

const manifest = {
  manifest_version: 2,
  version: "1.0",
  name,
  theme
};
zip.file("manifest.json", JSON.stringify(manifest, null, "  "));

return Promise.all(pendingImages)
  .then(() => zip.generateAsync({ type: "base64" }))
  .then(data => "data:application/x-xpinstall;base64," + data);
}</pre>



<p>So here, I add the code necessary to walk through any images in the theme and convert them to paths in <code>manifest.json</code> and accompanying image files in the archive. And then, at the end of the function, I use <code>Promise.all()</code> to resolve downloading images as necessary before generating the data: URL for the <code>.zip</code> archive.</p>



<hr class="wp-block-separator"/>



<p>By the way, to keep this entry short(er), I&#8217;m skipping the details on how all the above is used within our React &amp; Redux web app.</p>



<p>TL;DR: It&#8217;s a pretty nondescript async React &amp; Redux flow.</p>



<p>The export code lives in <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-e551cbd37d1de93c019232d073ec92aaR9">a function named <code>performThemeExport()</code></a>, used <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-dcca12df3924b59b9bfe6b554255be57R76">as input to an action creator</a>. A <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-3d865d12d9e63629e56e73e5ac213e3fR46">button click kicks off the process</a> by dispatching the action. Since the action&#8217;s payload begins as an unresolved promise, <a href="https://github.com/redux-utilities/redux-promise">the redux-promise middleware</a> handles resolving the payload before <a href="https://github.com/mozilla/FirefoxColor/pull/494/files#diff-75d32e6065a152c22e2a95712cf49991R178">updating the Redux store</a> (and thus the UI) when the export is finished.</p>



<hr class="wp-block-separator"/>



<p>All-in-all, getting this stuff to work was a surprise. Finding <a href="http://stuk.github.io/jszip/">JSZip</a> and figuring out how to do <a href="https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript/16245768#16245768">the various Base64 / binary conversions</a> were the pieces that really made it all fit together. While I&#8217;d seen those things before, they just hadn&#8217;t all slotted together in my head until just this afternoon.</p>



<p>Anyway, to wrap up: If you want to see all of this stuff in working form, you can follow along with <a href="https://github.com/mozilla/FirefoxColor/pull/494">the pull request I submitted to Firefox Color today</a>. It&#8217;s still rough, UX-wise, and will see further tweaks before we consider it done.</p>
]]></content:encoded>
			</item>
		<item>
		<title>Insultron2000 is here to serve!</title>
		<link>/2018/10/01/insultron2000-is-here-to-serve/</link>
		<pubDate>Mon, 01 Oct 2018 17:53:32 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[activitypub]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[bots]]></category>
		<category><![CDATA[dev]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[lambda]]></category>

		<guid isPermaLink="false">/?p=150</guid>
		<description><![CDATA[It was a rainy, chilly day this past Sunday. I had been meaning to work on Picodon. But I was feeling low enthusiasm for that project. So, I spun my Wheel of Side Projects. It landed on "ActivityPub insult bot"--a similar theme but it felt like something I could actually get working in a day. So, Insultron2000 was born!]]></description>
				<content:encoded><![CDATA[
<p>It was a rainy, chilly day this past Sunday. I had been meaning to work on <a href="https://github.com/lmorchard/picodon/">Picodon</a>. But I was feeling low enthusiasm for that project. So, I spun my <a href="https://wheel-of-side-projects.glitch.me/">Wheel of Side Projects</a>. It landed on &#8220;ActivityPub insult bot&#8221;&#8211;a similar theme but it felt like something I could actually get working in a day. So, <a href="https://github.com/lmorchard/insultbot">Insultron2000</a> was born!</p>



<p>I&#8217;ve also had &#8220;ActivityPub Lambda&#8221; on my maybe do list for awhile now. All the pieces are there in Amazon Web Services for a decent, low-maintenance ActivityPub node:</p>



<p>CloudFront can do SSL, caching, and use my own subdomain. An API gateway can handle all the inbox &amp; outbox parts of ActivityPub via Lambda functions. SQS can take care of the delivery work queue by feeding jobs to functions. CloudWatch alarms can trigger periodic scheduled functions. And then, there&#8217;s DynamoDB and S3 for storing &amp; publishing data.</p>



<p>While not <a href="https://typing.lmorchard.com/2018/09/26/embracing-stasis-to-get-unstuck/">as neglect-able as a fully static web site</a>, AWS seems to be cheap at hobby scale and easy to let lie fallow when I get bored with the project. By speaking ActivityPub directly, I don&#8217;t need to maintain a fediverse server like Mastodon or Pleroma. I don&#8217;t need to rely or impose on anyone else&#8217;s community server. It&#8217;s very light. I&#8217;ll be watching to see how the bill on this thing shakes out, but I expect it to cost pennies per year.<br/></p>



<p>I&#8217;m also hoping to refine this thing to be more generic. Push the ActivityPub machinery into the background. Support a simple local API for implementing future bots. Maybe reduce per-project code down to a single file with hooks for events and helpers for interacting with the fediverse.</p>



<p>This could even make it easier to stand up a single-user (or few-user) ActivityPub node. That&#8217;s also problem space at which Picodon is aimed: Lowering the trouble &amp; cost of fediverse participation. The main difference with Picodon is living on Glitch. Being there should mean that it&#8217;s easier (and more fun?) to remix your own version of it. Conversely, AWS is kind of a slog for tinkering. I mean, Ironically, AWS felt more fun this weekend&#8211;but I chalk that up to novelty vs fatigue.</p>



<p>I&#8217;ve also got some notions to see how much of this thing I can push into static hosting. Not the inbox / outbox endpoints that expect POST requests, of course. But, the ActivityStream objects and collections can be served up from a static S3 bucket or similar. Since everything in the ActivityPub protocol is generally addressable via arbitrary URLs like a good REST service, I should be able to gin up a somewhat generic service that could be dropped into an otherwise static site not unlike Disqus for comments.</p>



<p>Anyway, I could delve into more technical specifics here, but I think I&#8217;ll wrap up for now. If you&#8217;re interested, <a href="https://github.com/lmorchard/insultbot">come follow along at my GitHub repo</a>.</p>



<p>And if you&#8217;re up for a dumb insult, drop a mention to @Insultron2000@insultron.lmorchard.com on the fediverse!<br/></p>
]]></content:encoded>
			</item>
		<item>
		<title>Embracing stasis to get unstuck</title>
		<link>/2018/09/26/embracing-stasis-to-get-unstuck/</link>
		<pubDate>Wed, 26 Sep 2018 17:52:28 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[gutenberg]]></category>
		<category><![CDATA[metablogging]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">/?p=112</guid>
		<description><![CDATA[By letting things I've made go static, I can shed encumbrances to try new things. And I want to try new things to see if I can remove limiters on my writing.]]></description>
				<content:encoded><![CDATA[
<p>One of the reasons I stopped using WordPress was that I didn&#8217;t trust myself to leave code running in the cloud. I have a habit of wandering away and leaving things unpatched &amp; bitrotting for years. If only for that reason, a <a href="http://www.aaronsw.com/weblog/000404">baked-not-fried</a> personal web feels more responsible.</p>



<p><a href="https://decafbad.com/blog/2011/06/08/moved-to-jekyll/">I switched from WordPress to Jekyll</a>. But, since then, staring down a pile of Markdown files has felt like a limiter on my already diminished writing output. I thought using my favorite text editor would be comfortable &amp; fun. I&#8217;ve realized that <em>coding-me</em> and <em>writing-me</em> are different. Many affordances for programming are death-by-paper-cut for prosing.</p>



<p>Lately, I&#8217;ve done one of three things with ideas for writing:<br/></p>



<ul><li>Spew the raw idea directly onto Twitter</li><li>Write it down in my paper journal and keep it to myself</li><li>Promise myself to wrestle with Vim and blog machinery to refine the idea into a Proper Article<br/></li></ul>



<p>The mental drag of #3 converts every post into a <em>Project</em>. There&#8217;s little room for medium-sized things I might have published in the past. To counter this, I&#8217;d like to lower the friction between my head, the words, and the web.<br/></p>



<p>So. WordPress. It&#8217;s been awhile. <a href="https://wordpress.org/gutenberg/">Gutenberg</a> seems to jibe with how I&#8217;ve been thinking about web writing: Streams of components. Prose broken up with headings and images. A pull-quote or two. Some code samples and interactive widgets. Hell, maybe an embedded arcade game emulation from The Internet Archive.</p>



<p>In years past, trying WordPress &amp; Gutenberg called for a weekend spent converting all the things I&#8217;ve written so far to use the New Shiny as the Sole Instantiation of my Online Presence.</p>



<p>I&#8217;ve done this several times: From Movable Type to WordPress to Blosxom to PyBlosxom to WordPress to <a href="https://decafbad.com/blog/2011/06/08/moved-to-jekyll/">Jekyll</a> to <a href="https://decafbad.com/blog/2012/06/15/303-see-other/">WordPress</a> to <a href="https://blog.lmorchard.com/2014/10/20/static-blog-generation-with-gulp/">my own DIY thing that taught me how to use Gulp</a>. (Remember Gulp? <a href="https://blog.lmorchard.com/2015/02/09/parsec-patrol-resumes/">So 24 months ago</a>.) I&#8217;ve managed to keep a decade of writing intact as I moved the corpus between each of those systems. Kind of an achievement, I guess.<br/></p>



<p>Maybe it&#8217;s thanks to my career experience in the marketing side of web dev. It felt wrong to build anything but a cohesive monolith with a consistent brand identity and user experience. We were always refreshing and redesigning and never letting anything stay the way it was for long.<br/></p>



<p>I kind of hate that I ever did it that way for my own stuff. It&#8217;s not like I&#8217;m paying myself or even really learning much this way. This time I&#8217;ve decided to just start a new publication. Leave the old stuff be until I feel like messing with it again.</p>



<p><a href="https://blog.lmorchard.com/">And</a>, <a href="https://deus-x.livejournal.com/">it&#8217;s not like</a> <a href="https://decafbad.com/blog/">I don&#8217;t already</a> <a href="https://decafbad.com/bucket/">have plenty</a> <a href="https://decafbad.com/recaffeinated/">of publications</a> <a href="https://twitter.com/lmorchard/">out here</a> <a href="https://toot.lmorchard.com/@lmorchard/">on the web</a>, <a href="https://toot.cafe/@lmorchard/">anyway</a>.<br/></p>



<p>That brings me to some criteria of how my publications should work, going forward:</p>



<ul><li>Offer <a href="https://www.w3.org/Provider/Style/URI">cool URIs that don&#8217;t change</a>!</li><li>Live under a domain name that I control.</li><li>Live on the cheapest, dumbest web hosting.</li><li>Survive the obsolescence or disappearance of the authoring software.</li><li>Endure decades of complete neglect.<br/></li></ul>



<p>Standardizing on static websites can satisfy all these things. A few of my publications could use a one-time URL-breaking change to my own domains. And then there are things like Mastodon, which require active web services to keep working. Still, ideally, these are the things to shoot for.<br/></p>



<p>So, I&#8217;ve been playing with WordPress by installing it on the Synology NAS in my office. The thing you&#8217;re reading right now is a static website produced via <a href="https://wordpress.org/plugins/simply-static/">the Simply Static plugin</a>. I push the files out to Amazon S3 via some quick-and-dirty shell scripting. I&#8217;m thinking I&#8217;ll write more about this rig in a future post.<br/></p>



<p>This place looks different than <a href="https://blog.lmorchard.com/">the publication where I wrote my last big thing</a>. I&#8217;m telling myself this is okay. Maybe I&#8217;ll try <a href="https://ghost.org/">something like Ghost</a> for the next thing I write: Ghost does things with blocks &amp; cards now, too, so that&#8217;s interesting. That would look different and live on its own sub-domain, too. I&#8217;m telling myself that this is also okay.</p>



<p>So, to sum up: By letting things I&#8217;ve made go static, I can shed encumbrances to try new things. And I want to try new things to see if I can remove limiters on my writing. <br/></p>



<p>And why do I want to write more on the web? Well, that&#8217;s probably a notion for another post.<br/></p>
]]></content:encoded>
			</item>
		<item>
		<title>When Yak Shaving is The Point</title>
		<link>/2018/09/14/when-yak-shaving-is-the-point/</link>
		<pubDate>Fri, 14 Sep 2018 09:40:26 +0000</pubDate>
		<dc:creator><![CDATA[lmorchard]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[yakshaving]]></category>

		<guid isPermaLink="false">/?p=18</guid>
		<description><![CDATA[I've been working on some side projects lately. I feel good about that. But, I usually don't finish them. I feel bad about that. I always feel bad about that. But, maybe I shouldn't be so hard on myself.]]></description>
				<content:encoded><![CDATA[
<p>I&#8217;ve been working on some side projects lately. I feel good about that. But, I usually don&#8217;t finish them. I feel bad about that. I always feel bad about that. This tends to kills my motivation.<br/></p>



<p>Also, I keep thinking that on one of these projects, I&#8217;ll pull together a &#8220;Les Orchard Standard Boilerplate&#8221; with all my favorite things configured for my next project. But, almost every time, I throw together a new mix of language, frameworks, and modules that seems about as valid as my choices on other previous projects. From a certain perspective, this seems wasteful.<br/></p>



<p>Maybe I shouldn&#8217;t be so hard on myself. It&#8217;s not like I have <em>nothing</em> to show for this work. In fact, I think I&#8217;ve finally realized something obvious: This is my favorite way to stay current. That these side projects stop short of useful is beside the point. This is how I get experience applying recent frameworks and techniques, driven by scratching my own itches and following serial enthusiasms.</p>



<p>And though learning for its own sake is fun, I&#8217;ve found that my side projects end up being  leading indicators: The thing I played with a month ago comes in handy for next week&#8217;s work project. (And I <em>do</em> tend to finish my work projects, since I&#8217;ve got a team and a boss and a mission and a paycheck encouraging my focus.)<br/></p>



<p>Of course, sometimes I worry that this is just an intersection of confirmation bias and Stockholm syndrome: I often decide what stack to use for my projects at work. So, I could just be picking the things I&#8217;ve found most recently shiny. You know, I <em>have</em> made regrettable technology choices over the years. </p>



<p>I&#8217;m aware of this trap, though. So, I guess there&#8217;s another reason why I shake up the stack on every side project: I&#8217;m trying to keep myself from getting stuck on any particular combination. I&#8217;m trying to keep an open mind for possible benefits in the alternatives.</p>



<p>That brings me to the phrase that got stuck in my head this week: Yak shaving is the point. It&#8217;s not a distraction or a waste of time. It&#8217;s the yak shaving that sharpens the saw. </p>



<p>Okay now I&#8217;m mixing metaphors or idioms or whatever, but it makes sense to me at least!<br/></p>
]]></content:encoded>
			</item>
	</channel>
</rss>
