<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Alex Pounds' blog</title><link>https://alexpounds.com/blog</link><description>Alex Pounds' blog – links, photographs, and original writing.</description><language>en-gb</language><copyright>Copyright 2003-2026 Alex Pounds.</copyright><lastBuildDate>Fri, 11 Jun 2021 14:43:03 +0100</lastBuildDate><atom:link href="https://alexpounds.com/blog/rss" rel="self" type="application/rss+xml"/><item><title>Introducing Piccle</title><link>https://alexpounds.com/blog/2021/06/11/introducing-piccle</link><description><![CDATA[<p>I recently published Piccle, a static site generator for photographers. It's a commandline tool that uses the metadata within your photos to build a website. You can <a href="https://piccle.alexpounds.com">learn more &amp; try it out</a> or <a href="https://photography.alexpounds.com/">see it in action</a>, but I want to talk about the philosophy behind it.</p>

<h2 id="genesis">Genesis</h2>

<p>Photographers have many options for online services to share their work, but none align with the conversations I have about photography. If I'm talking with somebody &quot;about photography&quot;, that usually means a starting point like:</p>

<ul>
<li>&quot;I just bought a new camera, I really like it...&quot;</li>
<li>&quot;I went to Norway last year...&quot;</li>
<li>&quot;I take a lot of portraits...&quot;</li>
</ul>

<p>And I want to follow these up with &quot;Here, let me show you some photos.&quot;</p>

<p>This is harder than you might think! None of the major photo sharing sites<a href="#fn:10620" id="fnref:10620" title="see footnote" class="footnote"><sup>1</sup></a> make this easy, even though digital photos automatically contain a rich sea of metadata. &quot;Date taken&quot; and &quot;camera model&quot; is a given, and cameras increasingly add location info too. It's not much work for a human to add a description, title, and keywords when saving an edited image. But I don't think many people bother, because there's rarely a clear benefit.</p>

<p>It's a real shame that more sites don't use this metadata. Even if you only provide filtering or sorting by &quot;Date taken&quot;, this <a href="https://practicalpie.com/satisficing/">satisfices</a> for most of the use cases above<a href="#fn:27427" id="fnref:27427" title="see footnote" class="footnote"><sup>2</sup></a>. Sadly, the popular sites either cannot toggle between &quot;date taken&quot; and &quot;date uploaded&quot;, or hide the option away. Their focus seems to be &quot;display one image&quot;, not &quot;explore these works&quot;; navigating your photos by metadata is not a priority.</p>

<p>So what's your best option? Most sites &ndash; not Instagram &ndash; will let you collect photos into albums. This is tedious and pointless. Why should you have to manually add photos to albums like &quot;Taken in 2019&quot; or &quot;Trip to Norway&quot;? It's trivial for the computer to do it &ndash; processing and filtering data is <em>kind of their whole thing</em> &ndash; but no: the work is on you. It angers me when computers needlessly burden humans. I have filled out countless forms like this:</p>

<img src="/static/images/blog/2021/creditcard.png" alt="A screenshot of a credit card form, with an error message about spaces." />

<p>The computer knows what's up, but <em>I</em> still need to fix it? Just remove the non-numbers for me! Let me enter &quot;6011000990139424&quot; or &quot;6011 0009 9013 9424&quot;, and <em>you</em> can strip the spaces. You already <em>detected this specific case</em> to display the error message. Detect this specific case, <em>fix it</em>, and let's move on with our lives.</p>

<p>Another drawback to building albums is that your labour is on the <em>destination</em> &ndash; where your photos are displayed &ndash; rather than the <em>source</em> (the photos themselves). Storing metadata in your files makes it available everywhere &ndash; any site you upload to, any app you open, and the operating system itself. Cataloguing your photos on a third-party site isn't portable &ndash; if you spend years building up a well-organised Flickr profile and want to move elsewhere, you'll have to start from scratch<a href="#fn:12234" id="fnref:12234" title="see footnote" class="footnote"><sup>3</sup></a>.</p>

<h2 id="whatiwanted">What I wanted</h2>

<p>I was unhappy with how existing web services presented my photography. They would show individual images nicely, but didn't let people explore my body of work. I didn't enjoy posting to them, and it never felt like I had a good place to link people when talking about photography. I also wanted to host the portfolio myself; you never know when an external service will wither away, be acquired, or shut down abruptly. And if your main &quot;online home&quot; is a third-party service, your audience is not your own<a href="#fn:29041" id="fnref:29041" title="see footnote" class="footnote"><sup>4</sup></a>.</p>

<p>When a web developer starts thinking along these lines &ndash; a self-hosted, explorable photography portfolio &ndash; the big temptation is to build a &quot;proper&quot; web app. Something database-backed, with dynamic pages. It's doable, but there are multiple tar pits:</p>

<ul>
<li>There's a strong temptation to build an admin interface to manage and edit your photo's metadata. This is a classic example of something which sounds easy<a href="#fn:13848" id="fnref:13848" title="see footnote" class="footnote"><sup>5</sup></a>, but isn't. The reason third-party sites do a bad job is because this is <em>hard</em>, not because they haven't thought of it.</li>
<li>It suggests a lot of customisability, and now you are hurtling towards &quot;content management system&quot; rather than &quot;show off my photos&quot;.</li>
<li>It's hard for people to try it on their own photos. They must download your software, set up a database, set up a web server, add their photos, and run it. (You can make this a little easier with something like Docker &ndash; but now you're presuming they're familiar with Docker).</li>
<li>It's hard for people to host it. If they want to publish their site &ndash; not just try it out &ndash; they need the technical skills to configure it on the external host.

<ul>
<li>As well as needing a dynamic web server and a database, they must also deal with photo files. This means they either need to configure their server to allow uploads, or set up something like an S3 bucket too.</li>
<li>How do people preview something before publishing? You have two tricky options: export photos from your local instance to a remote instance, or include the concept of &quot;preview&quot; vs. &quot;published&quot;. Now we're back in &quot;content management system&quot; territory.</li>
<li>How do you handle backups? An import/export system might help with that local instance &rarr; hosted instance problem, but it's yet another thing to code. And part of the problem is that you have both <em>data</em> and <em>content</em>; some database content, and some image files. So either you're crafting some kind of specialised binary blob or creating a ZIP file with a manifest &ndash; both of which seem somewhat fragile.</li>
<li>Once they've got it working, it must <strong>stay working</strong>. Your code must persevere through language, system, and database upgrades. You need to think about cross-version compatibility and dealing with updates.</li>
</ul></li>
</ul>

<p>In short: your photographer is now a sysadmin.</p>

<p>&quot;Stay working&quot; is important. It's not enough for your software to work; it must <em>keep working</em>. If any of it breaks &ndash; the database, the web server, your web app &ndash; the user doesn't have a portfolio any more. And this content rarely changes &ndash; how often are you publishing photos? The keenest photographer posts a few times a day at most<a href="#fn:30655" id="fnref:30655" title="see footnote" class="footnote"><sup>6</sup></a>. Why not generate a static site instead?</p>

<p>A database-backed website is <em>software</em>. A static site is a <em>document</em>. The former's <em>alive</em> &ndash; it only works when the software runs &ndash; and the latter is <em>dead</em> (it works as long as some other software is alive to read it). This neatly sidesteps a lot of the issues above: hosting static files is the most basic form of web hosting, both for a provider<a href="#fn:15462" id="fnref:15462" title="see footnote" class="footnote"><sup>7</sup></a> and an individual. There's no performance tuning or system administration. It's easy to try out and preview (view the generated site on your own computer) and easy to publish (copy the files to your webhost). And your portfolio is frozen in time &ndash; but still works as-is &ndash; if the generator breaks.</p>

<h2 id="mostlydead">Mostly dead</h2>

<p>Permit me a tautology: a static site is <em>static</em>. The code doesn't change unless someone regenerates it from new data. You might think this sounds dull, flat, and lifeless &ndash; but it doesn't have to be. Books are also static, as are movies and albums. Harry Potter, Die Hard, and Rumours are the same every time but feel vividly alive. Your static site can be the same.</p>

<p>Even though we're generating static files, we can include features that make it feel more alive. An Atom feed lets users subscribe for updates; including OpenGraph tags gives informative previews when people share links. CSS transitions &amp; animations can give visual pizazz, and you can use a smattering of JavaScript for features like slide shows.</p>

<p>You could go further, and build a JavaScript-driven single page app. When people think of SPAs, they think of JavaScript talking to an HTTP API. But the API is optional: our JavaScript can read a static JSON file instead. After the initial page load we can render everything in the browser, returning only to the server for images. This gives you the best of both worlds: the speed and reliability of a server-rendered site, combined with the slickness of client-side rendering. All the contemporary JavaScript options are available to you, if you want them.</p>

<p>I still don't know if <em>I</em> want them, though I've designed Piccle with the presumption I do. The idea of switching to client-side rendering after the initial page load is attractive; it's the progressive enhancement dream scenario. The question is: is it worth loading a megabyte of JSON for that<a href="#fn:269" id="fnref:269" title="see footnote" class="footnote"><sup>8</sup></a>? Piccle already feels snappy when changing pages, and the HTML is very light. I'll experiment, but it might not be an improvement.</p>

<h2 id="whatibuilt">What I built</h2>

<a href="/static/images/blog/2021/picclescreenshot.png"><img src="/static/images/blog/2021/picclescreenshot.thumb.png" alt="A screenshot of my photography portfolio, showing a grid of images and navigation." /></a>

<p>Piccle is a command-line utility built in Ruby. Given a directory of images, it generates a complete site. There's still a database under the hood, but acting as a cache instead of powering the website directly.</p>

<p>One command generates your site, but it's a multi-step process internally:</p>

<ol>
<li>New and updated metadata is extracted from the photos to the database.</li>
<li>The photos are faceted based on an aspect of the metadata (eg. &quot;camera model&quot;, &quot;date&quot;, &quot;location&quot;). Each facet is implemented as its own &quot;stream&quot;, which groups photos according to its facet. Streams are <a href="https://github.com/creature/piccle/blob/0d3c68cd931139089e18f9bf4d614274ec3622b2/bin/piccle#L188-L197">registered upfront</a>; then, as each photo is added, <a href="https://github.com/creature/piccle/blob/master/lib/piccle/parser.rb#L62-L65">the stream adds its own data</a>.</li>
<li>The website is generated. This uses a NodeJS helper utility for performance reasons. (There's a pure Ruby renderer available too, but it's impractically slow for more than a handful of photos.)</li>
</ol>

<p>Earlier versions supported serving a website from the database, but some queries (and working both statically &amp; dynamically) were too unwieldy. It was simplest to abandon that approach.</p>

<p>I describe Piccle as a zero-configuration tool, but that's a lie. There are <a href="https://github.com/creature/piccle#available-options">some customisations available</a>. &quot;Events&quot; are the most notable &ndash; named date ranges, handy for <a href="http://photography.alexpounds.com/by-event/pride-portraits/">themed shoots</a> or <a href="http://photography.alexpounds.com/by-event/thailand-2019/">trips</a>. I don't know a good way to store these in EXIF data, so events are defined in YAML instead. Generating a gallery from one command makes it easier to slot Piccle into your existing workflow &ndash; you can set an <a href="https://support.apple.com/en-gb/guide/automator/welcome/mac">Automator action</a> to watch a directory for new files and then run Piccle. Add an <code>rsync</code> command too: now your photo is automatically published to the web the instant you export your photo from your image editor.</p>

<p>Overall, there's nothing technically revolutionary in Piccle. The value is in how lots of small elements come together to be pleasant to use. Good help text and sensible defaults in the interface; responsive output so galleries look great on phones, tablets, and desktops. Quilt images for each subsection, so shared links look good.</p>

<img src="/static/images/blog/2021/messagesquilt.png" alt="A screenshot from iMessage, showing the quilt." />

<p>But at a higher level, I want to hide all of this from users. Piccle should feel obvious; <em>of course</em> social media shares look good. <em>Of course</em> you run one command and get a complete site that's easy to deploy. <em>Of course</em> you can browse by date, location, and tags. Photographers shouldn't need to know anything about web development, or databases, or programming. They should feel like Piccle is a small tool doing one thing well &ndash; even if, underneath, it's working hard to do ten things well.</p>

<h2 id="builtforeverybodyandyetnot">Built for everybody, and yet not</h2>

<p>A static site is a good technical fit for a photo gallery. It's also simpler for users: &quot;run once and put the output on the web&quot; is easier than &quot;keep this database-backed system running.&quot; Simplicity is one of my goals for Piccle; I want to bring better tools to more people, to make it easier for people to host their own photo galleries. From one perspective, I achieved this: Piccle takes a directory of images and generates a nice-looking website with one command. Publishing HTML is easier than hosting a CMS or a Docker container. If you have some photos in a folder you can try it easily. The generated gallery is OK even if your photos have limited metadata.</p>

<p>But I mentioned Piccle to a friend a couple of months ago, and she said &ldquo;Let me know when it&rsquo;s ready &amp; I&rsquo;ll get the people in my camera club to test it.&rdquo; This should have been delightful, but I was deeply reluctant.</p>

<p>A camera club is a group of people who own complicated equipment, are enthusiastically operating them, and are technical enough to transfer photos onto a computer &amp; edit them using specialist software. Yet there's a huge distance between them and someone who finds Piccle easy to use. How many camera club members already use a command line? How many will have Ruby and NodeJS installed? For me, Piccle is straightforward<a href="#fn:17076" id="fnref:17076" title="see footnote" class="footnote"><sup>9</sup></a>. But if you&rsquo;re not like me, it&rsquo;s arcane.</p>

<p>I built Piccle for my own use, but I'm bothered by this gulf between my goal &ndash; break down publishing obstacles &ndash; and the result. Imagine you're a member of that camera club: you&rsquo;re into photography, you have your photos on your computer, and you want to make a website for them. Your side quests include:</p>

<ul>
<li>Learn enough about the CLI to navigate directories and run commands.</li>
<li>Install Ruby and NodeJS (or check your OS includes them).</li>
<li>Install Piccle. Hopefully all of its dependencies install cleanly &ndash; otherwise you&rsquo;ll need to chase down things like ImageMagick and SQLite libraries.</li>
<li>Find a suitable web host, set up an account, and figure out how to upload all your files in one go.</li>
<li>Figure out how to integrate all of this into your workflow. To be useful this can&rsquo;t be a one-time process; it&rsquo;s got to be repeated, and reliable, and feel natural.</li>
</ul>

<p>I don&rsquo;t have a solution for this. Packaging Piccle up into a GUI and shipping static versions of Ruby/Node/etc is one possibility<a href="#fn:1883" id="fnref:1883" title="see footnote" class="footnote"><sup>10</sup></a>. It&rsquo;s not how I want to use Piccle, but it would open it up to a wider audience. This is an open question, and one I&rsquo;m still mulling over.</p>

<h2 id="nextsteps">Next steps</h2>

<p>Now that I&rsquo;ve launched Piccle I&rsquo;ve swung back towards photography rather than coding: editing past images and adding metadata to existing shots. It's satisfying seeing it become closer to a comprehensive archive of my photography, and it&rsquo;s taught me more about my own work than I expected. This is an ideal outcome: it's nice when programming sparks an interest in programming, but better when it sparks an interest in creativity. Nothing's better than when a computer inspires you to create.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:10620">
<p>Flickr is the exception here; they have superb filtering tools. But it's not a perfect solution: you have to pay if you want more than 200 photos visible, the filters aren't easy to find, and you can't host it yourself. <a href="#fnref:10620" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:27427">
<p>&quot;I just bought a new camera&quot; implies &quot;show me the most recent photos&quot;. You can probably recall the rough month/year of a trip, so jumping to a given date works for travel. <a href="#fnref:27427" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:12234">
<p>Or hope that your new home has written a special importer, just for Flickr. <a href="#fnref:12234" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:29041">
<p>There's a philosophy called <a href="https://indieweb.org/POSSE">POSSE</a> &ndash; &quot;Publish Own Site, Syndicate Elsewhere.&quot; It boils down to &quot;Keep your creative stuff on your own domain, and federate it out.&quot; Your blog should live on your own website. Publish your articles on Medium, Substack, Wordpress, etc. if you like &ndash; but keep the canonical version on your own website. Ideally, you get the best of both worlds: the increased audience from the third-party sites, and the control inherent in first-party hosting. It's not as popular as it was, but it still has a lot of appeal for me. <a href="#fnref:29041" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:13848">
<p>To a programmer. <a href="#fnref:13848" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:30655">
<p>Editing takes time, and if people do produce a lot of work in one go they're likely to publish it as one batch. <a href="#fnref:30655" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:15462">
<p>Any webhost can host static files &ndash; as can Amazon S3, Github Pages, or Geocities. <a href="#fnref:15462" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:269">
<p>You can split the JSON and load chunks on-demand, but why? You could load the actual page instead. <a href="#fnref:269" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:17076">
<p>I am a programmer, spend a lot of time on the command line, and generally wish for a simpler time on the internet. <a href="#fnref:17076" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:1883">
<p>This sounds tricky to implement across Windows, Mac, and Linux. <a href="#fnref:1883" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2021/06/11/introducing-piccle</guid><pubDate>Fri, 11 Jun 2021 14:43:03 +0100</pubDate></item><item><title>Sudbury's Eiffel Tower</title><link>https://alexpounds.com/blog/2020/12/31/sudburys-eiffel-tower</link><description><![CDATA[<p>I recently passed through Sudbury, Ontario. We visited the <a href="https://en.wikipedia.org/wiki/Big_Nickel">Big Nickel</a>.</p> 

<img src="/static/images/blog/2020/bignickel.jpg" alt="The Big Nickel in Sudbury" />

<p>On our way out of town I spotted this structure. Was it... the Tiny Eiffel Tower? 

<img src="/static/images/blog/2020/antenna.jpg" alt="A tower curiously reminiscent of the Eiffel Tower" /> 

<p><a href="https://mapio.net/pic/p-18587066/">Alas no</a>:

<blockquote>Actually, it&rsquo;s a custom-built antenna tower to communicate with the cement trucks of Wavy Industries by VHF FM radio. Commissioned by philanthropic millionaire Owner Clifford Fielding in the mid 1970s. Designed & built by Toronto&rsquo;s Trylon Mfg. Ltd.</blockquote>
Still, maybe the greatest thing about the internet is its ability to answer questions like these.</p>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2020/12/31/sudburys-eiffel-tower</guid><pubDate>Thu, 31 Dec 2020 23:37:37 +0000</pubDate></item><item><title>Two small photography-related scripts</title><link>https://alexpounds.com/blog/2019/12/31/two-photography-scripts</link><description><![CDATA[<p>I just added a <a href="https://github.com/creature/useful-scripts">couple of small photography-related scripts to Github</a> &ndash; one for photo organisation, and one for generating preview galleries. Every photographer has their own workflow, so these are more useful as starting points for your own tools rather than something to use out of the box. They're easier to adapt with some backstory.</p>

<h2 id="howisortmyphotos">How I sort my photos</h2>

<p>When I finish a photoshoot<a href="#fn:5102" id="fnref:5102"><sup>1</sup></a>, I copy the photos into a directory with a datestamp and a title. For instance:</p>

<ul>
<li>20190617 - Raptors victory parade</li>
<li>20190728 - fire spinners</li>
<li>201911 - Thailand</li>
</ul>

<p>Next, I pick the photos I want to edit. I use <a href="https://www.macrumors.com/how-to/files-folders-tags-macos/">macOS' filesystem tags</a> to organise these into two categories &ndash; &quot;definitely&quot; (for my best shots) and &quot;maybe&quot; (for shots with potential). Tags are great:</p>

<ul>
<li>They're part of the OS &ndash; so you can use them in searches, in file &rarr; open dialogs, and so on. One click in the Finder sidebar shows me my edit queue.</li>
<li>You're not locked into one app for organisation, making it easier to change apps or use multiple editors.</li>
<li>Your tags get backed up as part of your regular Time Machine backups.</li>
<li>Tags are attached to individual files, so if you copy photos to an external drive the tags are copied too.</li>
<li>You can interact with tags programatically, so you can build your own tooling on top of them.</li>
</ul>

<p>The Finder's built-in tools are enough to sort through my photos from small photoshoots. Open a Finder window, switch it to thumbnail mode, maximise the zoom, and resize to get two photos per row. Then select a file, and press <key>space</key> to open <a href="https://support.apple.com/en-ca/guide/mac-help/mh14119/10.14/mac/10.14.6">Quick Look</a> to check out the photo. If you like it, right-click &rarr; click a tag to add.</p>

<p><img src="/static/images/blog/2019/findertags.png" alt="A screenshot of a Finder window, showing the maximum zoom for filtering images"</p>

<p>This doesn't work so well for larger photoshoots. It isn't easy to winnow down your selections<a href="#fn:21909" id="fnref:21909"><sup>2</sup></a>, and you move between the keyboard and the mouse a lot.</p>

<p>I use <a href="https://affinity.serif.com/en-gb/photo/">Affinity Photo</a> as an image editor, and I really like it. But I recently picked up a copy of <a href="https://exposure.software">Exposure X5</a>, mostly for its many film presets/colour grades (including some <a href="https://fujilove.com/fujifilm-presets-in-exposure-x3/">passable imitations</a> of my camera's built-in presets). Affinity Photo's similar to Photoshop, whereas Exposure's more like Lightroom &ndash; which means it's also capable of organising your images and <a href="https://exposure.software/tutorial/fast-photo-culling/">faster winnowing</a>. Load a directory of images, sort through them applying flags/ratings, then filter down to the flagged/rated images and upgrade/remove the ratings to suit. There's keyboard shortcuts for these, so it's potentially faster &ndash; though Exposure seems to do a poor job of pregenerating RAW previews, so I've found some frustrating delays.</p>

<p>If you did this in Lightroom, those ratings would be stored in Lightroom's central catalog. Exposure, however, stores all its metadata alongside your files. This makes it much easier to work with programatically! I wrote a small script, <code>tagsfromexposure</code>, which reads Exposure data and creates filesystem tags. Flagging an image as &quot;pick&quot; in Exposure translates to &quot;definitely&quot;; 2 stars or above translates to &quot;maybe&quot;. This uses the <a href="https://github.com/jdberry/tag/"><code>tag</code> command line utility</a> for tagging, as it looked complicated in standard Ruby.</p>

<h2 id="generatingpreviewgalleries">Generating preview galleries</h2>

<p>Once I've picked my photos, I generate a preview gallery for online sharing. If it was a &quot;proper&quot; photoshoot, this lets my model pick their favourites for me to edit; if it was a day out or a trip abroad, I can share the good shots with family &amp; friends. I dislike image editing and I'm a slow editor, so most of my photos would never be seen if I didn't <a href="http://ethicsgirls.com/">publish these previews</a>.</p>

<p><code>albumfromtags</code> uses <a href="https://sigal.saimon.org/en/latest/">Sigal</a> to generate these galleries based on macOS tags. Anything with a &quot;maybe&quot; or &quot;definitely&quot; tag gets included. This script also uses the <code>tag</code> utility to read filesystem tags. It copies the images to a new directory, uses Sigal to generate the gallery, then removes the temporary directory. You'll need to customise the <code>sigal.conf.py.example</code> file to add your name for the gallery's copyright notice, save it somewhere permanent, and edit the <code>albumfromtags</code> file to point to the config.</p>

<p>----------</p>

<p>One thing I like about these scripts &amp; this workflow is that it's very modular. I've taken several unrelated tools, and used a small amount of code to glue them together so they work for me. They're easy to extend and change. There's no custom data formats involved &ndash; just the operating system's features. These are all <a href="https://homepage.cs.uri.edu/~thenry/resources/unix_art/ch01s06.html">unixy approaches</a> to building tools &ndash; an approach as useful in 2019 as it was in 1989.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p>This can be an actual photoshoot, or a day out, or a trip abroad, or whatever. I also keep monthly &quot;miscellaneous Toronto&quot; directories for my handful of day-to-day shots around the city. <a href="#fnref:5102" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:2">
<p>For instance, if you have 3 good portraits of someone in a particular pose, there's a lot of clicks and filters needed to tag all 3 as &quot;maybe&quot; and then later upgrade one to &quot;definitely&quot;.  <a href="#fnref:21909" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2019/12/31/two-photography-scripts</guid><pubDate>Tue, 31 Dec 2019 18:55:00 +0000</pubDate></item><item><title>Four Cool URLs</title><link>https://alexpounds.com/blog/2018/12/29/four-cool-urls</link><description><![CDATA[<p>One of the things I've always found elegant about programming is how small, simple elements can be combined to accomplish complicated tasks. Sometimes this is a compound elegance (like stringing unrelated UNIX commands together to achieve your goal); sometimes it's an atomic elegance (like someone using something simple in a way you never imagined).</p>

<p>URLs have been around for <a href="https://tools.ietf.org/html/rfc1738">more than 20 years</a>. They're <a href="https://tools.ietf.org/html/rfc3986">a method of &quot;identifying a resource&quot;</a>, which means &quot;unambiguously pointing to something on the internet.&quot; That's how they're normally used: URLs point to websites, articles, images, songs, videos, downloads &ndash; everything. Most people don't give them much thought, in part because web browsers increasingly hide URLs away. But some URLs have special powers. Here are some that knock my socks off.</p>

<h2 id="goodhertz&ndash;vulfcompressorpresethttps:goodhertz.covulf-comp2.0.1cm:90wf:0out:-7.5cat:8cre:1.3csl:0drl:0"><a href="https://goodhertz.co/vulf-comp/2.0.1/?cm:90/wf:0/out:-7.5/cat:8/cre:1.3/csl:0/drl:0">Goodhertz &ndash; Vulf Compressor preset</a></h2>

<pre><code>https://goodhertz.co/vulf-comp/2.0.1/?cm:90/wf:0/out:-7.5/cat:8/cre:1.3/csl:0/drl:0
</code></pre>

<p>Goodhertz is a company that makes audio processing plugins<a href="#urlfn:1" id="urlfnref:1" title="see footnote" class="footnote"><sup>1</sup></a>. Presets let people save their favourite sounds, share them with others, and keep them safe so they can revisit the settings later. They're also a great way to learn: if you want to learn how someone got a great sound, they can show you the settings.</p>

<p>This URL is cool for a couple of reasons: first up, <em>it's a preset in itself</em>. Pass it to the audio plugin, and the plugin uses the settings from the URL. But it's also a valid web page<a href="#urlfn:2" id="urlfnref:2" title="see footnote" class="footnote"><sup>2</sup></a> that shows the settings used, in a more human-readable format. This is great for learning, and if you find yourself in a niche situation<a href="#urlfn:3" id="urlfnref:3" title="see footnote" class="footnote"><sup>3</sup></a> it might make your life easier.</p>

<h2 id="reddit-rredditlaqueristashttps:reddit.comrredditlaqueristas"><a href="https://reddit.com/r/redditlaqueristas">Reddit - /r/redditlaqueristas</a></h2>

<pre><code>https://reddit.com/r/redditlaqueristas
</code></pre>

<p>There's nothing specific about the Laqueristas subreddit that made me select it, beyond it being a great example of an online interest-specific community. I could have picked any Reddit URL for this demo &ndash; and indeed, that's what makes this URL cool. Take any Reddit URL, append <code>.json</code> to it, and you'll get back a JSON version:</p>

<pre><code>https://reddit.com/r/redditlaqueristas.json
</code></pre>

<p>This is a really user-friendly way of exposing an API! It makes it easy for programmers to get started &ndash; no need to register an API key, set up oAuth, or anything like that. Those barriers are often counterproductive (as people will just scrape the web pages rather than jump through those hurdles). It's not just subreddits &ndash; if you want to retrieve user details, or the contents of a post, it works there as well. Removing a <code>.json</code> can be useful too: if you're trying to debug some code that interacts with Reddit, you can take the relevant link and turn it back into a form designed for human consumption rather than trying to read through the JSON.</p>

<p>The concept of <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation">content negotiation</a> has been around for a while, where you can do this via the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept">HTTP <code>Accept</code> header</a>, but I'd really like to see more of it. Wouldn't it be neat to get a PDF version of your receipt by appending <code>.pdf</code> to the URL? Websites can use <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types"><code>&lt;link rel=&quot;alternate&quot;&gt;</code></a> to expose these other versions to the world, though sadly most browsers don't communicate those alternate versions to users.</p>

<h2 id="combine.fmhttps:combine.fmspotifyalbum4pxqad8t4hfkealqiec7mm"><a href="https://combine.fm/spotify/album/4PXQAD8t4hfKeAlQiEc7mM">Combine.fm</a></h2>

<pre><code>https://combine.fm/spotify/album/4PXQAD8t4hfKeAlQiEc7mM
</code></pre>

<p>It seems the idea of an open music web is pretty much dead. It's all closed silos these days: there's no interoperability between Spotify, YouTube, Apple Music, Soundcloud, and so on. If you're sharing a track with a friend, what do you do? Generally, the most practical solution is to send a YouTube link. That tends to work OK, but isn't ideal<a href="#urlfn:4" id="urlfnref:4" title="see footnote" class="footnote"><sup>4</sup></a>. You could send them a link to your preferred service, but they might use a different one. And you probably don't keep track of which friend uses which service.</p>

<p>Enter Combine.fm. You hand it a link to something on a music service:</p>

<pre><code>https://open.spotify.com/album/4PXQAD8t4hfKeAlQiEc7mM
</code></pre>

<p>And it gives you links to that music on all the services it can:</p>

<pre><code>https://combine.fm/spotify/album/4PXQAD8t4hfKeAlQiEc7mM
</code></pre>

<p>Now your friend can click through to their music provider and play what you shared. That's a cool service, but look at the URL: it's pretty similar to the Spotify one.</p>

<p>This means you don't need to use Combine.fm to construct a Combine.fm URL &ndash; you can do it yourself, or write a script to handle it. If the Combine.fm service disappears or changes, you haven't lost a link to your music &ndash; the original ID is intact.</p>

<h2 id="traintimes.org.ukhttps:traintimes.org.uklondonbrighton11:30today"><a href="https://traintimes.org.uk/london/brighton/11:30/today">Traintimes.org.uk</a></h2>

<p>Traintimes.org.uk is a site that provides &quot;accessible UK train timetables&quot;. It's an unofficial site, but I vastly prefer it to <a href="http://www.nationalrail.co.uk/">National Rail Enquiries</a>. It's got a simple visual design and works great without JavaScript &ndash; which means it's a tiny web page. Tiny web pages are quick to load, and work well even on poor 3G coverage. Just what you need if you're in the middle of nowhere trying to figure out a route home.</p>

<p>The URL is cool because it's designed to be human editable. Let's look at trains from London to Brighton:</p>

<pre><code>https://traintimes.org.uk/london/brighton/11:30/today
</code></pre>

<p>Do you happen to know the official 3 letter code for London Bridge, and want to travel from that station specifically? You can drop that in:</p>

<pre><code>https://traintimes.org.uk/LBG/brighton/11:30/today
</code></pre>

<p>Do you want to leave a couple of hours later? That's also an easy change:</p>

<pre><code>https://traintimes.org.uk/LBG/brighton/13:30/today
</code></pre>

<p>Are you actually planning for tomorrow? Change the last part.</p>

<pre><code>https://traintimes.org.uk/LBG/brighton/13:30/tomorrow
</code></pre>

<p>This is all documented <a href="https://traintimes.org.uk/">on the front page of the site</a>, but you don't need to know these details to use the service. There's a friendly form to start your search, and the results page lets you navigate to earlier or later trains (along with the return trip). But a user interface that tried to cater for every use case would be cluttered, and supporting URL editing doesn't cost anything. If you use the site often enough to be familiar with it the URLs, it's often quicker to edit the URL rather than perform a fresh search.</p>

<hr />

<p>We can see some general principles at work in these URLs:</p>

<ul>
<li><strong>A URL points to a thing, but it can also be the thing itself</strong>. In the Goodhertz case, the preset was the URL (and the URL was the preset). A page of search results is a more prosaic example: the results displayed match the parameters for the search in the URL.</li>
<li><strong>URLs can be for both human and machine consumption</strong>. The Goodhertz URL is primarily for consumption by software &ndash; the plugin that uses the preset. The Traintimes URL is designed to be easy for a human to manipulate. The Reddit page is a hybrid: easy for a human to transform into a computer-friendly format by adding <code>.json</code> to the end.</li>
<li><strong>URLs can be robust</strong>. Even if the Combine.fm service fails or dies, you can easily return to the original links.</li>
<li><strong>URLs can be predictable</strong>. You don't need API documentation to get started with Reddit's API. You don't need to involve Combine.fm to generate a valid Combine.fm link. If you learn the format of the Traintimes links, you could type one in by hand.</li>
<li><strong>Let power users edit your URLs</strong>. Most Reddit or Traintimes users aren't going to retrieve JSON or explore times by editing the URL, but power users can do so. There's no extra cost to that apart from the initial design, and your users benefit from having the option.</li>
<li><strong>Good URLs are descriptive</strong>. The Traintimes URL describes the results you'll see. Even if you've never visited the site, you can make a reasonable guess about what <code>https://traintimes.org.uk/london/brighton/11:30/today</code> would show you.</li>
</ul>

<p>These principles aren't applicable to every scenario. Sometimes a link <em>is</em> just a pointer to a particular document online. A news website would find it hard to let users edit their links in a meaningful way. And sometimes you want your URLs to be hard to predict (for instance, you don't want people to guess the links to your Google docs).</p>

<p>URLs are consumed by machines, but they should be designed for humans. If your URL thinking stops at &quot;uniquely identifies a page&quot; and &quot;good for SEO&quot;, you're missing out. </p>

<div class="footnotes">
<hr />
<ol>

<li id="urlfn:1">
<p>Software that changes sound. Want to add an echo effect? Make your vocals sound like a robot? Make your audio sound like it's underwater? These plugins are one way of accomplishing that. <a href="#urlfnref:1" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="urlfn:2">
<p>Some software constructs strings that look like URLs to store info, and the software can use the URL, but it doesn't lead to a working web page. Those always make me sad. <a href="#urlfnref:2" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="urlfn:3">
<p>&quot;My laptop doesn't have an internet connection in the studio, but I only have this preset on my phone. Do I have to type it all out by hand? Oh cool, I can see the settings on my phone &amp; use the interface to set them all.&quot; <a href="#urlfnref:3" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="urlfn:4">
<p>The quality can be iffy, it might get taken down due to copyright claims, it might not be available in their territory. They can't add it to a playlist, save it to their music library, or listen in the background when on a mobile device. Plus it's video rather than audio, so it's not mobile-data-friendly. <a href="#urlfnref:4" title="return to body" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>

]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2018/12/29/four-cool-urls</guid><pubDate>Sat, 29 Dec 2018 23:18:21 +0000</pubDate></item><item><title>A review of Beyerdynamic's Byron headphones</title><link>https://alexpounds.com/blog/2017/12/31/beyerdynamic-byron-headphones-review</link><description><![CDATA[<p>I bought a pair of <a href="http://amzn.to/2CjS1de">Beyerdynamic Byrons</a><sup><a href="#fn:66981" id="fnref:66981">1</a></sup> this year, and I hate them. But before I explain why, I'm afraid we must explore my history of headphones. </p>

<p>I've used and loved a pair of Sennheiser HD280s at home &amp; work for over a decade. Two pairs, in fact; <a href="https://twitter.com/acreature/status/568091112432373760">one pair broke</a> after a respectable 8 years of daily usage. They're great: amazing sound, solid build quality, <a href="http://spares.sennheiser.co.uk/pro-audio-headphones/hd-280-pro">spare parts are available</a>, people nearby can't hear your music, and they smother enough ambient noise to make open-plan offices more peaceful. But they are indoor headphones: they look ridiculous if worn outside, and they're too bulky for that anyway. So the Sennheisers live on my desk, and I use earbud headphones when out in the world. </p>

<p>The particular choice of earbuds has varied through the years. I used <a href="http://amzn.to/2BZIcNd">some Sennheisers</a> for a while, and they were fine. When I got an iPhone the convenience of the remote/microphone made me switch to the included <a href="https://en.wikipedia.org/wiki/Apple_earbuds#Apple_EarPods">EarPods</a>. And I liked them a lot! The sound was acceptable, the remote/mic was useful<sup><a href="#fn:83788" id="fnref:83788">2</a></sup>, and the build quality was good. Well, the build quality was OK. Kind of OK. Not... not that OK. </p>

<p>The earpieces themselves are solid, and the remote's always worked fine. But I've owned several pairs of EarPods, and they all end up like this: </p>

<a href="/static/images/blog/2017/iphoneheadphones.jpg"><img src="/static/images/blog/2017/iphoneheadphonestmb.jpg" alt="The EarPods, with heatshrink" /></a>

<p>Designers generally include <a href="http://www.connector.com/effective-strain-relief-design/">strain relief</a> when a cable meets a plug. This prevents the wire from being pulled into sharp angles and getting damaged. The EarPods have this too, but it's just a small piece of rubber. Over time, this gets broken and splits off. Then the headphones start to cut out in one ear, and the remote goes wild when you're not touching it. It's easy enough to add some <a href="https://en.wikipedia.org/wiki/Heat-shrink_tubing">heatshrink</a> to compensate for this if you have a nearby Hackspace, and this fixes things for a while, but you're now on borrowed time. The cable will fail, and your headphones will crackle or be silent. </p>

<p>I've gone through at least 3 sets of EarPods since 2012, and when my latest pair started to fail I decided enough was enough. Surely I could spend a little more, and get something that doesn't consistently fail in the same way? I knew I didn't want Apple's AirPods<sup><a href="#fn:596" id="fnref:596">3</a></sup>, so I looked around, read some reviews, and settled on <a href="http://amzn.to/2CjS1de">Beyerdynamic's Byron headphones</a>. Around $65 from Amazon, compared to $35 for the EarPods. </p>

<p>When looking around, here's what I thought my priorities were: </p>

<ol>
<li>They've got to sound good. They don't have to be amazing<sup><a href="#fn:17403" id="fnref:17403">4</a></sup>, but it's got to be good. At least as good as the EarPods.</li>
<li>They've got to have a remote.</li>
<li>They've got to have decent build quality. If I'm spending a bit more money, they should last longer than the EarPods.</li>
<li>They've got to be wired. I don't need another gadget to charge in my life, and can deal with trailing cables.</li>
</ol>

<a href="/static/images/blog/2017/byronheadphones01.jpg"><img src="/static/images/blog/2017/byronheadphones01tmb.jpg" alt="Beyerdynamic's Byron headphones" /></a>

<p>Let's start with their good points. They've got a slightly longer cable, which was more convenient than I expected. The build quality seems stronger, particularly around the plug. Just look at that strain relief! It's going to last way longer than the EarPods. They cut down a lot of outside noise &ndash; great for plane/coach trips &ndash; and they're more comfortable to sleep with. Finally, the sound quality can be great. There's been a couple of times when I've listened to music I knew well, and I heard something new &ndash; something I'd missed even on my big Sennheisers. That's strong praise.</p>

<p>But despite these upsides, I cannot recommend them. More than that: I feel that <strong>people must be warned</strong>. It turns out I had a greater priority, one I never realised. One I never thought to enumerate: </p>

<ol start="0">
<li>They've got to stay in your ears.</li>
</ol>

<p>And they don't! They just don't. Whenever I go for a run they fall out constantly, and I look like a newscaster who thinks he's lost contact with the studio. These headphones are pushed into the ear canal, yet still fall out constantly. The EarPods just sat on your ear-shelf, but <strong>never</strong> fell out. It's genuinely baffling, and it fills me with anger. The Byron's earpieces are made from grippy rubber, they fit tightly, and have more surface area in contact with the ear. Yet they're not as secure as the EarPods? How is that possible? It's not just running, either: it happens when walking around the city too. Not as much, but it's still a notable flaw. </p>

<p>But let's put that to one side, and return to the sound quality. I said before it can be great - but it can also be terrible. The Byrons will sound great when sitting at <em>exactly</em> the right point in your ears. Too deep, and they will be thuddy and dull and overbearing. And if they're loosening &ndash; which they will be &ndash; they're just empty, with nothing but high frequencies. But that's not all: if the cable moves <em>at all</em> you'll get an annoying constant sub-bass rumble. This is annoying on a treadmill, and a bit irritating at other times. I'm not convinced this is a problem specific to the Byrons &ndash; I suspect it's a problem with all in-canal headphones &ndash; but it's still a reason not to buy them. </p>

<p>Beyerdynamic <a href="https://support.beyerdynamic.com/hc/en-us/articles/212535725-Can-I-also-use-other-eartips-than-those-included-">themselves recommend</a> that you could buy some alternative ear pieces for sports. I briefly considered this, before realising that it was <em>completely bananas</em> to spend another $20 in the hope that these headphones were not a lost cause. You get 3 sizes of ear pieces in the box and I have tried them all. None of them seem to make any difference. </p>

<p>The remote is another problem &ndash; though this one's my fault. The Byrons are designed for Android phones. This really means that a <a href="http://www.cablechick.com.au/blog/understanding-trrs-and-audio-jacks/">couple of the connections in the TRRS jack are transposed</a>, so the remote/mic won't work with Apple devices. I should have read the description more closely before buying, and I could live with a non-functional remote. But the remote works! To different levels on every device!</p>

<ul>
<li>On my iPhone, the remote acts completely normally. Yaaaaay.</li>
<li>On my iPad, the volume buttons don't work but the play/pause button does.</li>
<li>On my laptop, the volume buttons move the volume in the correct direction, but don't stop moving it. So I have a &quot;Turn sound off&quot; or &quot;Destroy my ears&quot; buttons.</li>
</ul>

<p>As I say: my fault. But if it's going to work weirdly, could it at least be consistent? Or maybe include an adapter in the box, if Android/Apple compatibility is just a case of transposing two connections? </p>

<p>Finally, let's take a closer look at the headphones after a month or so of use. </p>

<a href="/static/images/blog/2017/byronheadphones02.jpg"><img src="/static/images/blog/2017/byronheadphones02tmb.jpg" alt="Byron headphones, looking into the drivers" /></a>

<p>Look closely at the driver on the top. No mesh! Somehow, the mesh has fallen out somewhere. I don't know how I'll try to clean this when it gets gunky. I've also managed to lose two of the rubber cups somewhere &ndash; so now both ears fit poorly <em>and</em> differently. An asymmetrical annoyance.</p>

<p>I bought a pair of Beyerdynamic Byrons this year, and I hate them.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:66981">
<p>This is an affiliate link, as other the other Amazon links in this article. If you follow it to the Byrons, I recommend you buy something else.  <a href="#fnref:66981" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:83788">
<p>Extremely useful after I switched to a MacBook Pro. I always had the EarPods on me, so I always had an acceptable Skype headset. Perfect for surprise calls wherever I was. <a href="#fnref:83788" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:596">
<p>Which discombobulates me, as they have <a href="https://www.macrumors.com/2017/05/01/airpods-98-percent-satisfaction-rate/">astonishingly good reviews</a>, but I don't think they'd work for me. I worry about them falling out when running/cycling, I would miss the remote, and I <em>really</em> don't want to own something that needs to be charged several times a day. <a href="#fnref:596" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:17403">
<p>Sound quality is pretty closely tied to the size of the driver, so in-ear headphones will almost always sound worse than over-ear headphones. <a href="#fnref:17403" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2017/12/31/beyerdynamic-byron-headphones-review</guid><pubDate>Sun, 31 Dec 2017 18:33:12 +0000</pubDate></item><item><title>Exploring weird maths with code </title><link>https://alexpounds.com/blog/2016/09/04/exploring-weird-maths-with-code</link><description><![CDATA[<script>
  var linkElement = document.createElement("link");
  linkElement.rel = "stylesheet";
  linkElement.href = "//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.6.0/styles/default.min.css";
  document.head.appendChild(linkElement);
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.6.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

<p>Sometimes, while reading an innocuous-seeming article, I stumble across an aside that makes me sit bolt upright and mutter something incredulous. Asides like this one: </p>

<blockquote>
<p>A counterintuitive property of coin-tossing: If Alice tosses a coin until she sees a head followed by a tail, and Bob tosses a coin until he sees two heads in a row, then on average, Alice will require four tosses while Bob will require six tosses (try this at home!), even though head-tail and head-head have an equal chance of appearing after two coin tosses.</p>
&mdash; <em><a href="http://www.wired.com/2016/03/mathematicians-discovered-prime-conspiracy/">Wired</a></em></p>
</blockquote>

<p>This <em>was</em> a surprise! The four possible outcomes of two tosses are equally likely, so it seems weird that a heads-tails outcome would take longer to reach than a heads-heads. Weird enough to try it at home &ndash; at least by programming. Let's write some Ruby and see if we get the same result. (I recommend opening <a href="https://en.wikipedia.org/wiki/Interactive_Ruby_Shell"><code>irb</code></a> and exploring these examples for yourself if you want to fully understand them.)</p>

<h2 id="checkingsomeassumptions">Checking some assumptions</h2>

<p>First of all, let's agree to toss a coin by picking a random symbol from an array<sup><a href="#weirdfn:1" id="weirdfnref:1" title="see footnote" class="footnote">1</a></sup>: </p>

<pre><code class="ruby">def coin_toss
  %i(heads tails).sample #=&gt; :heads or :tails. 
end
</code></pre>

<p>And let's confirm that this is close enough to 50/50, by counting the result of tossing a coin 100,000 times:</p>

<pre><code class="ruby">results = {heads: 0, tails: 0}
1000000.times { results[coin_toss] += 1 }

puts &quot;After 100000 tosses we saw #{results[:heads]} heads and #{results[:tails]} tails.&quot;
</code></pre>

<p><a href="https://ruby-doc.org/core-2.3.1/Array.html#method-i-sample"><code>.sample</code></a> chooses an element at random, so the result will be a little different each time. I ran this program 10 times, and got these results: </p>

<pre><code class="nohighlight">After 100000 tosses we saw 50131 heads and 49869 tails.
After 100000 tosses we saw 49845 heads and 50155 tails.
After 100000 tosses we saw 50094 heads and 49906 tails.
After 100000 tosses we saw 49672 heads and 50328 tails.
After 100000 tosses we saw 50062 heads and 49938 tails.
After 100000 tosses we saw 50046 heads and 49954 tails.
After 100000 tosses we saw 50003 heads and 49997 tails.
After 100000 tosses we saw 50094 heads and 49906 tails.
After 100000 tosses we saw 50124 heads and 49876 tails.
After 100000 tosses we saw 49838 heads and 50162 tails.
</code></pre>

<p>I think these results <em>look</em> OK, but the next thing I tried was busting out some statistics and checking the <a href="https://en.wikipedia.org/wiki/Standard_deviation">standard deviation</a>. You can think of it as a measure of how closely-clustered our results are &ndash; we'd expect to get a low standard deviation if <code>.sample</code> is fair. Calculating the standard deviation is a little bit complicated, so I used the <a href="https://github.com/thirtysixthspan/descriptive_statistics"><code>descriptive_statistics</code> gem</a> to make it easier. Let's calculate the standard deviation of the number of heads in each run: </p>

<pre><code class="ruby">require 'descriptive_statistics'
[50131, 49845, 50094, 49672, 50062, 50046, 50003, 50094, 50124, 49838].standard_deviation #=&gt; 146.014
</code></pre>

<p>But is 146.014 low or not? I have no idea! This is where my statistics knowledge runs out. For now, let's presume our eyeballs are correct and our coin tosses are fair.</p>

<h2 id="backtothequestion">Back to the question</h2>

<p>If we can toss a coin fairly, we can return to our original question: how many tosses, on average, does it take to reach a given combination?</p>

<p>We'll need a target combination, we need to toss at least twice, and we want to toss until we hit the target: </p>

<pre><code class="ruby">target = [:heads, :heads]
tosses = [coin_toss, coin_toss]

until tosses.last(2) == target
  tosses &lt;&lt; coin_toss
end
</code></pre>

<p>I ran this in <code>irb</code> and I got <code>[:tails, :tails, :heads, :tails, :heads, :heads]</code>. It works! Let's turn this into a method so we can reuse it: </p>

<pre><code class="ruby">def tosses_until(target)
  tosses = [coin_toss, coin_toss]
  until tosses.last(2) == target
    tosses &lt;&lt; coin_toss
  end
  tosses
end
</code></pre>

<p>Running the experiment repeatedly will make our result more reliable. If something weird happens once it could be a fluke, but you can't fluke something thousands of times. We could use the <code>.times</code> method again, and build up an array of results like we built the array of tosses: </p>

<pre><code class="ruby">experiments = []
100000.times { experiments &lt;&lt; tosses_until([:heads, :heads]) }
</code></pre>

<p>Or we can make this shorter by using <a href="http://ruby-doc.org/core-2.3.1/Enumerable.html#method-i-map">Ruby's <code>.map</code> method</a>. <code>.map</code> applies a method to every element in a list. It's normally used to modify an existing list:</p>

<pre><code class="ruby">[&quot;cat&quot;, &quot;dog&quot;, &quot;avocado&quot;].map { |t| t.upcase } #=&gt; [&quot;CAT&quot;, &quot;DOG&quot;, &quot;AVOCADO&quot;]
(1..4).map { |n| n * 3 } #=&gt; [3, 6, 9, 12]
</code></pre>

<p>But it doesn't matter if we throw the original elements away instead. You can try this in the console, but beware! It's going to print out all 100,000 results.</p>

<pre><code class="ruby">experiments = (0..100000).map { tosses_until([:heads, :heads]) }
</code></pre>

<p>It's not really relevant to our experiment, but I wondered what the shortest and longest sequence until our target was. You might expect that we can use <code>experiments.min</code> and <code>experiments.max</code> to find out: </p>

<pre><code class="ruby">experiments.min #=&gt; [:heads, :heads]
experiments.min.length #=&gt; 2
experiments.max #=&gt; [:tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :heads, :tails, :heads, :tails, :heads, :heads]
experiments.max.length #=&gt; 21
</code></pre>

<p>But that's not quite right<sup><a href="#weirdfn:2" id="weirdfnref:2" title="see footnote" class="footnote">2</a></sup> for the maximum case. It <em>looks</em> right, though &ndash; a handy reminder that verifying data by eye can lead you astray. Instead, we need to use <code>.max_by</code> to explicitly look at the length of the array: </p>

<pre><code class="ruby">experiments.max_by { |e| e.length }
</code></pre>

<p>This pattern &ndash; calling a method on the value passed into the block &ndash; is common, so Ruby provides a shorthand for this: </p>

<pre><code class="ruby">experiments.max_by(&amp;:length) #=&gt; [:heads, :tails, :tails, :tails, :heads, :tails, :tails, :tails, :heads, :tails, :tails, :tails, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :heads, :tails, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :heads, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :tails, :heads, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :tails, :heads, :heads]
experiments.max_by(&amp;:length).length #=&gt; 61
</code></pre>

<p>Let's put all this together in one place, and add some output about our results:</p>

<pre><code class="ruby">def coin_toss
  %i(heads tails).sample #=&gt; :heads or :tails. 
end

def tosses_until(target)
  tosses = [coin_toss, coin_toss]
  until tosses.last(2) == target
    tosses &lt;&lt; coin_toss
  end
  tosses
end

experiments = (0..100000).map { tosses_until([:heads, :heads]) }
average_toss_count = experiments.reduce(0) { |sum, n| sum + n.length } / experiments.length.to_f # We'll talk about this line below.

puts &quot;Our shortest sequence was #{experiments.min_by(&amp;:length)}&quot;
puts &quot;Our longest sequence was #{experiments.max_by(&amp;:length)}&quot;
puts &quot;On average, we had to toss #{average_toss_count} times before (heads, heads) came up.&quot;
</code></pre>

<p><a href="https://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-reduce"><code>.reduce</code></a> is a close cousin of <code>.map</code>. <code>.map</code> does something to every element in a list; <code>.reduce</code> takes two elements from a list and boils them down into one. It does that repeatedly to produce a final value:</p>

<pre><code class="ruby">[1, 2].reduce { |a, b| a + b } #=&gt; 3
[1, 2, 3].reduce { |a, b| a + b } #=&gt; 6: [1, 2, 3] &rarr; [3, 3] &rarr; 6.
[1, 2, 3, 4].reduce { |a, b| a + b } #=&gt; 10: [1, 2, 3, 4] &rarr; [3, 3, 4] &rarr; [6, 4] &rarr; 10.
</code></pre>

<p>You can also give <code>.reduce</code> a starting value, which is what we did in our program: </p>

<pre><code class="ruby">[1, 2].reduce(10) { |sum, a| sum + a } #=&gt; 13: 10 + 1 = 11 then 11 + 2 = 13.
[1, 2, 3].reduce(10) { |total, a| total + (a * 2) } #=&gt; 22.
</code></pre>

<p>We started our toss count at 0, then added the length of each run to that total. Finally, we divided it by the total number of runs to get an average. The <code>.to_f</code> on the end converts the length to a <a href="http://floating-point-gui.de/formats/fp/">floating point number</a>, because we'd like to see the decimal places in the result. </p>

<pre><code class="ruby">9 / 2 #=&gt; 4; really &quot;4 remainder 1&quot;, but Ruby throws the remainder away
9 / 2.to_f #=&gt; 4.5
</code></pre>

<h2 id="simplifyingourcode">Simplifying our code</h2>

<p>This works, but is more complicated than it needs to be. Our goal was to find out <em>how many</em> tosses, on average, it takes to hit our target &ndash; we don't care about the <em>sequence</em> of tosses to get there. Let's change our <code>tosses_until</code> method to return the number of tosses instead of the sequence itself: </p>

<pre><code class="ruby">def tosses_until(target)
  tosses = [coin_toss, coin_toss]
  until tosses.last(2) == target
    tosses &lt;&lt; coin_toss
  end
  tosses.length
end
</code></pre>

<p>This lets us make our trial run code simpler. We could build an array of the sequence counts, then add it up:</p>

<pre><code class="ruby">experiments = (0..100000).map { tosses_until([:heads, :heads]) }
average_toss_count = experiments.reduce(&amp;:+) / experiments.length.to_f
</code></pre>

<p>We could skip the array entirely, and just maintain a total: </p>

<pre><code class="ruby">total_experiments = 100000
total_tosses = 0
total_experiments.times { total_tosses += tosses_until([:heads, :heads]) }
average_toss_count = total_tosses / total_experiments.to_f
</code></pre>

<p>Or we could use <code>reduce</code> again:</p>

<pre><code class="ruby">total_experiments = 100000
total_tosses = (0..total_experiments).reduce(0) { |sum, _| tosses_until([:heads, heads]) }
average_toss_count = total_tosses / total_experiments.to_f
</code></pre>

<p>The &quot;best&quot; version is a matter of taste, but personally I prefer the first version. It uses more memory, but that doesn't matter in experiments like these. It's the shortest code, we can find the longest run of tosses, and it's reasonably clear how it works once you get your head around <code>.reduce</code>.</p>

<p>Let's put the first version into a method that runs the experiment and reports the outcome for a given target:</p>

<pre><code class="ruby">def coin_toss
  %i(heads tails).sample
end

def tosses_until(target)
  tosses = [coin_toss, coin_toss]
  until tosses.last(2) == target
    tosses &lt;&lt; coin_toss
  end
  tosses.length
end

def average_toss_count(target, num_experiments)
  experiments = (0..num_experiments).map { tosses_until(target) }
  average_toss_count = experiments.reduce(&amp;:+) / experiments.length.to_f

  # sprintf formats the average so it prints to two decimal places only.
  puts &quot;On average, we had to toss #{sprintf('%.2f', average_toss_count)} times before #{target.inspect} came up. Our longest run was #{experiments.max} tosses.&quot;
end
</code></pre>

<h2 id="theothercases">The other cases</h2>

<p>Now we have all the building blocks to run the experiment for each of the four possible outcomes:</p>

<pre><code class="ruby">targets = [[:heads, :heads], [:heads, :tails], [:tails, :heads], [:tails, :tails]]
targets.each { |target| average_toss_count(target, 100000) }
</code></pre>

<p>Which produces:</p>

<pre><code class="nohighlight">On average, we had to toss 5.98 times before [:heads, :heads] came up. Our longest run was 52 tosses.
On average, we had to toss 4.00 times before [:heads, :tails] came up. Our longest run was 22 tosses.
On average, we had to toss 3.99 times before [:tails, :heads] came up. Our longest run was 20 tosses.
On average, we had to toss 6.00 times before [:tails, :tails] came up. Our longest run was 55 tosses.
</code></pre>

<p>Sure enough, it takes longer on average to hit <code>[:heads, :heads]</code> or <code>[:tails, :tails]</code> than <code>[:heads, :tails]</code> or <code>[:tails, :heads]</code>, even though each outcome has an equal probability. It's still weird, but now I'm satisfied it's true.</p>

<h2 id="whydoesthishappen">Why does this happen?</h2>

<p>Let's go back to Alice and Bob, who are targeting <code>[:heads, :tails]</code> and <code>[:heads, :heads]</code> respectively:</p>

<table class="weirdcode">
<thead>
<tr>
	<th>Player</th>
	<th>Target</th>
</tr>
</thead>

<tbody>
<tr>
	<td>Alice</td>
	<td>H T</td>
</tr>
<tr>
	<td>Bob</td>
	<td>H H</td>
</tr>
</tbody>
</table>

<p>Let's presume they both win their first toss &ndash; they both get a result they're looking for:</p>

<table class="weirdcode">
<thead>
<tr>
	<th>Player</th>
	<th>Target</th>
	<th>Result 1</th>
</tr>
</thead>

<tbody>
<tr>
	<td>Alice</td>
	<td>H T</td>
	<td>H</td>
</tr>
<tr>
	<td>Bob</td>
	<td>H H</td>
	<td>H</td>
</tr>
</tbody>
</table>

<p>Then, presume they lose their second toss: </p>

<table class="weirdcode">
<thead>
<tr>
	<th>Player</th>
	<th>Target</th>
	<th>Result 1</th>
	<th>Result 2</th>
</tr>
</thead>

<tbody>
<tr>
	<td>Alice</td>
	<td>H T</td>
	<td>H</td>
	<td>H</td>
</tr>
<tr>
	<td>Bob</td>
	<td>H H</td>
	<td>H</td>
	<td>T</td>
</tr>
</tbody>
</table>

<p>There's now a major difference between the two players: Alice can hit her target on toss 3, but Bob <strong>can't until toss 4</strong>. Bob must start over after losing on toss 2; Alice's loss can be part of a win if she gets a tails on turn 3.</p>

<h2 id="exercises">Exercises</h2>

<p>If you'd like to explore this some more, here's some suggestions for things to try:</p>

<ol>
<li>Change the program so it runs the experiment a million times instead of 100,000.</li>
<li>If we toss three coins, there's eight possible outcomes. How long does it take, on average, to hit each combination? Are there some sequences that take longer than others?</li>
<li>We left our proof of a fair coin toss at &quot;Yeah, that looks OK.&quot; Can you do better? How would you satisfy yourself that it's producing fair results?</li>
</ol>

<div class="footnotes">
<hr />
<ol>

<li id="weirdfn:1">
<p><code>%i()</code> is Ruby shorthand that generates an array of symbols. <code>%i(foo bar baz)</code> means the same as <code>[:foo, :bar, :baz]</code>. <a href="#weirdfnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="weirdfn:2">
<p>But why doesn't this work? When we call <code>.min</code>, Ruby <a href="https://ruby-doc.org/core-2.3.1/Enumerable.html#method-i-min">uses the <code>&lt;=&gt;</code> comparison operator</a> to find the smallest value in the list. <code>experiments</code> is an array of arrays; <code>&lt;=&gt;</code> for arrays <a href="https://ruby-doc.org/core-2.3.1/Array.html#method-i-3C-3D-3E">calls <code>&lt;=&gt;</code> on each of the elements of the list in turn until it finds a difference</a>. In this case, our list elements are symbols. Symbols get <a href="https://ruby-doc.org/core-2.3.1/Symbol.html#method-i-3C-3D-3E">converted to strings before comparison</a>, and <code>&quot;heads&quot; &lt; &quot;tails&quot;</code> because <code>&quot;h&quot; &lt; &quot;t&quot;</code>. So the upshot of this is that <code>experiments.max</code> returns the result with the longest initial streak of tails.<p>
<p>Yes, I had to look this up in the documentation. <a href="#weirdfnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2016/09/04/exploring-weird-maths-with-code</guid><pubDate>Sun, 04 Sep 2016 00:55:45 +0100</pubDate></item><item><title>The EU Referendum: A Retrospective</title><link>https://alexpounds.com/blog/2016/06/30/the-eu-referendum-a-retrospective</link><description><![CDATA[<p>I have tried for days to write about the referendum, but I keep getting overwhelmed by the immensity of it. Will we actually leave, or <a href="https://www.washingtonpost.com/news/worldviews/wp/2016/06/26/an-astute-online-comment-has-many-wondering-whether-brexit-may-ever-happen/">prevaricate forever</a>? Can we negotiate reasonable trade deals, or will the EU <a href="http://www.news.com.au/finance/economy/world-economy/european-union-facing-dilemma-ahead-of-brexit-talks-warned-against-punishing-uk/news-story/e8da765deb28287c2f96a67d193d44fb">make an example out of us</a>? Will <a href="https://www.theguardian.com/business/2016/jun/26/city-of-london-expecting-further-post-brexit-losses-when-trade-reopens">companies still open offices in the UK</a> now we're no longer a gateway to Europe? Will <a href="http://www.irishtimes.com/news/world/uk/call-for-scottish-independence-vote-another-big-headache-for-eu-1.2701900">Scotland become independent</a>? What happens next in <a href="http://www.newstatesman.com/politics/uk/2016/06/overlooking-effect-brexit-northern-ireland-dangerous-whole-uk">Ireland</a>? Will our <a href="http://www.bbc.com/news/uk-england-cornwall-36616955">most deprived regions</a> <a href="http://news.sky.com/story/1717526/regions-demand-uk-govt-matches-lost-eu-funds">keep their funding</a>? Will <a href="https://www.theguardian.com/commentisfree/2016/jun/06/leave-campaign-workers-rights-brexiters-british">workers' rights be protected</a>? Any one of these would be Pandora's box; we have opened many at once. </p>

<p>All of these issues are important, and all of these are beyond my control. They're also beyond my foresight: I have no idea what happens next. The <a href="https://next.ft.com/content/314ed068-3c2d-11e6-8716-a4a71e8140b0">stock market is suffering</a> and <a href="http://www.economist.com/blogs/buttonwood/2016/06/markets-after-referendum">the pound is at a thirty year low</a>. These falls came from the decision to leave, but the <a href="http://www.bbc.com/news/business-36648630">fluctuation</a> comes from the uncertainty. Uncertainty is the UK's greatest national resource now. We can certainly export that to the world.</p>

<figure><a href="https://twitter.com/gameoldgirl/status/747027708337586176"><img src="/static/images/blog/2016/frontpages.jpg" alt="A collage of anti-EU, anti-migrant front pages from UK newspapers." /></a>
<figcaption>Nothing says tolerance, compassion, and decency like <a href="http://www.newstatesman.com/blogs/the-staggers/2010/07/express-british-national-party">calling people &quot;Ethnics&quot;</a>. Collage via <a href="https://twitter.com/gameoldgirl/status/747027708337586176">@gameoldgirl</a>.</figcaption></figure>

<p>Everyone promptly found out that <a href="http://www.theguardian.com/politics/2016/jun/27/eu-referendum-reality-check-leave-campaign-promises">the &quot;leave&quot; campaign was a Potemkin village</a>, but its shoddy foundations were laid over the previous decades. The tabloid press constantly pumped out anti-EU &amp; anti-immigrant froth, and nobody found a way to combat it effectively. Politicians found they could use these fears to their advantage, so why try to dispel them? Besides, it would invite the wrath of the press. </p>

<p>Without this backdrop &ndash; a nation flooded by freeloaders, powerless to prevent pointless meddling from Brussels &ndash; the UK would never vote to leave. It would have sounded preposterous. It was our government alone that failed to invest in the NHS, to build houses and schools, to make sure our <a href="http://www.perc.org.uk/project_posts/thoughts-on-the-sociology-of-brexit/">post-industrial regions weren't dependent on grants</a>, and allowed employment to become <a href="https://www.theguardian.com/uk-news/2016/mar/09/uk-workers-on-zero-hours-contracts-rises-above-800000">more precarious</a>. Nothing to do with Europe. But it's no surprise that the people on the losing end of <a href="https://www.theguardian.com/uk/2013/may/12/two-speed-britain-london-soars">rising inequality</a> would vote against the status quo.</p>

<h2 id="asausergiventhatihaveatimemachine">As a user, given that I have a time machine...</h2>

<p>I've grappled with two questions since Thursday night: &quot;What should I<a href="#eureffn:1" id="eureffnref:1"><sup>1</sup></a> have done differently?&quot; and &quot;What should I<a href="#eureffn:1"><sup>1</sup></a> do now?&quot;. I'd kept my own counsel in previous elections but I spoke up a little this time. Some of that was amongst friends, but I also made <a href="https://europe.alexpounds.com">a small website</a> that laid out the benefits of European co-operation. I tried to back up all my claims, but my goal was to change people's feelings &ndash; not their minds. I wanted undecided people to see this long list and think &quot;Wow, I never realised that the EU had a part in all this&quot;. People in the UK think of the EU as faceless, ineffectual, meddling bureaucrats who force legislation upon us; I hoped to replace that with some affection.</p>

<p>The site was a small success. It reached a couple of thousand people, and <a href="https://www.reddit.com/r/unitedkingdom/comments/4p4fcl/theres_hundreds_of_things_that_the_eu_does_for/">sparked some discussion</a> showing it reached folk who weren't voting &quot;remain&quot; already. But I can't shake the feeling that my aim was off. Older people are more likely to vote, and more likely to vote &quot;leave&quot; &ndash; but they're harder to reach through the internet, and I don't have a voice in traditional media. People outside of large cities were more likely to vote &quot;leave&quot; &ndash; but they're harder to reach as my social circle is very urban. What could I have done differently to reach those groups? What medium should I have used? Would a different message have resonated more?</p>

<figure><img src="http://www.brixtonbuzz.com/images/brits-dont-quit-bremain-01.jpg">
<figcaption>This campaign seriously impressed me. It's so simple, but appeals directly to the viewer's sense of identity. Just three words and a picture of Churchill speak volumes about persevering through tough times and standing with our neighbours.</figcaption></figure>

<p>Or is this the wrong question? Instead of asking how to reach a different audience, perhaps it's better to convince my audience they need to vote. My gut says that's a harder problem &ndash; people have been <A href="http://www.economist.com/blogs/economist-explains/2014/10/economist-explains-24">trying to motivate the younger generation to participate in politics unsuccessfully</a> for years. Transforming online activism into real-world action is Herculean. I don't know what I can do as an individual, but Facebook's &quot;I voted&quot; feature is the strongest encouragement I've seen online. </p>

<h2 id="whatdowedonow">What do we do now?</h2>

<p>I doubt we'll see a second referendum. We'd need to negotiate a new deal with the EU &ndash; one different enough to merit putting it to the vote again. But Europe <a href="http://www.telegraph.co.uk/news/2016/06/25/europe-prepares-fast-and-painful-deal-for-britain/">wants us out and doesn't need to negotiate with a gun to its head</a>. We already had many <a href="https://en.wikipedia.org/wiki/Opt-outs_in_the_European_Union">exceptions to EU rules</a> but voted to leave anyway. So Europe has no motivation to offer us a deal, and no pro-EU politician will want to risk a second &quot;leave&quot; outcome. We might hope for a stalemate &ndash; the UK never invoking Article 50, the EU not finding a way to <a href="https://next.ft.com/content/7badcbe2-3a0b-11e6-9a05-82a9b15a8ee7">force us out</a> &ndash; but I expect some combination of economic uncertainty &amp; European resentment will result in Britain leaving the EU.</p>

<p>Journalists and politicians will try to identify the effects of leaving, but conclusive evidence will be scarce. You can't see the corporate headquarters that gets built in France instead, nor can you see the uncreated jobs from a lack of economic growth. Businesses don't fail for one reason alone. Infrastructure takes at least a decade to become obviously dated; too slow to recognise and attribute.</p>

<p>Individuals can't change the UK's situation, but we can make our communities better. I have four concrete suggestions:</p>

<ul>
<li><a href="http://www.unitedagainstracism.org/archive/pages/info30.htm">Stand up for others</a> when you see <a href="https://www.theguardian.com/uk-news/2016/jun/27/sadiq-khan-muslim-council-britain-warning-of-post-brexit-racism">abuse and prejudice</a>.</li>
<li>Talk with your friends and neighbours about your beliefs. Don't proselytise; just listen to what they say, and gently try to move their opinions a little. Be compassionate and polite. You're trying to show people that there's a huge range of perspectives in the world, and to dispel myths &amp; fears.</li>
<li>Lobby your MP to focus on their constituency instead of party politics. MPs need to support job security and job creation. They need to protect worker's rights and the social safety net. <a href="https://writetothem.com/">Let them know you expect this of them</a>.</li>
<li>Hold the people who got us into this mess to account. They convinced us to leave, but don't want the responsibility of figuring out the details or standing by their pledges. And don't forget the <a href="http://www.independent.co.uk/news/people/eu-referendum-nigel-farage-branded-shameful-for-claiming-victory-without-a-single-bullet-being-fired-a7099211.html">disgusting parts</a> either.</li>
</ul>

<p>I also have an idea for another project. Something that makes it easier for people to engage with the politics that affects them, not the Westminster soap opera. I don't know if it will see the light of day, but I'm trying to use my anxiety about the future to propel it forward. It might not help after all, but anything's better than just looking on in horror.</p>

<div class="footnotes">
<hr />
<ol>

<li id="eureffn:1">
<p>&quot;I&quot; really means &quot;we&quot;: &quot;what should an individual citizen, acting in their country's best interest, have done differently?&quot; <a href="#eureffnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2016/06/30/the-eu-referendum-a-retrospective</guid><pubDate>Thu, 30 Jun 2016 05:41:38 +0100</pubDate></item><item><title>How to Expand an OSX FileVault partition on El Capitan</title><link>https://alexpounds.com/blog/2016/05/07/expanding-osx-filevault-partitions-on-el-capitan</link><description><![CDATA[<p>I switched to OSX as my primary operating system around a year ago, after a lifetime of running Linux on the desktop. Using Ubuntu on a Macbook Pro is surprisingly straightforward and didn't require any low-level finagling, but it did come with some annoyances; annoyances that led me to try OSX as my primary OS. I kept the dual boot, but over time I wanted more disk space available to OSX. I had to piece the process together every time; here's what worked for me.</p>

<h2 id="step0:takeagoodbackup">Step 0: take a good backup.</h2>

<p>Editing partitions carries a risk of losing all your data. Backup everything! In both operating systems! These steps worked for me, but might not work for you. And while we're talking precautions: choose a time when you don't have important deadlines, meetings, or other computer-centric tasks.</p>

<h2 id="step1:makespaceonthedrive">Step 1: make space on the drive.</h2>

<p>You need free space for your OSX partition to expand into. The disk utility in OSX is limited and can't resize Linux partitions, but <a href="http://gparted.org">GParted</a> can. I downloaded <a href="http://www.ubuntu.com/download/desktop">Ubuntu</a> and <a href="http://www.ubuntu.com/download/desktop/create-a-usb-stick-on-mac-osx">made a bootable USB key</a>. Plug it in, then reboot while holding down the <key>option &#8997;</key> key. You can then choose a device to boot from.</p>

<p>Once in Linux, my process was: </p>

<ol>
<li>Clear some space on the Linux partition beforehand, then shrink it in GParted.</li>
<li>Move the now-smaller partition to the end of the drive.</li>
<li>Move any other partitions (eg. OS X recovery partitions) towards the end of the drive, so there's unallocated space after the partition you want to expand. Something like this<a href="#osxfilevaultfn:1" id="osxfilevaultfnref:1" class="footnote"><sup>1</sup></a>:</li>
</ol>

<img src="/static/images/blog/2016/gparted.png" alt="A screenshot of gparted, showing some unallocated space." />

<p>GParted will let you queue up these changes and try to apply them all in one go, but that gave me some (apparently harmless) error messages. I'd recommend making the changes one at a time.</p>

<h2 id="step2:rebootintoosxandturnoffcorestorage">Step 2: reboot into OSX and turn off CoreStorage.</h2>

<p>OSX uses a <a href="https://en.wikipedia.org/wiki/Core_Storage">volume manager</a> called CoreStorage that acts as an intermediary between the operating system and the hardware. It's a requirement for <a href="https://en.wikipedia.org/wiki/Filevault">FileVault</a> encryption, but we can't expand drives while it's enabled. First, let's see all the CoreStorage volumes using <code>diskutil cs list</code> on the terminal:</p>

<pre><code>CoreStorage logical volume groups (2 found)
|
+-- Logical Volume Group UUID 9559695B-73C6-40ED-B6EB-F3DE8767058A
|   =========================================================
|   Name:         Macintosh HD
|   Status:       Online
|   Size:         249222377472 B (249.2 GB)
|   Free Space:   0 B (0 B)
|   |
|   +-&lt; Physical Volume UUID A76BF102-C0CF-41C4-9D88-27F8BB9A180E
|   |   ----------------------------------------------------
|   |   Index:    0
|   |   Disk:     disk0s2
|   |   Status:   Online
|   |   Size:     249222377472 B (249.2 GB)
|   |
|   +-&gt; Logical Volume Family UUID EDA455C5-3FD0-444E-B00C-F9F8F2EF88EC
|       ----------------------------------------------------------
|       Encryption Type:         AES-XTS
|       Encryption Status:       Unlocked
|       Conversion Status:       Complete
|       High Level Queries:      Fully Secure
|       |                        Passphrase Required
|       |                        Accepts New Users
|       |                        Has Visible Users
|       |                        Has Volume Key
|       |
|       +-&gt; Logical Volume UUID 4F3C168A-F0BB-40B6-B3FF-CE94D38506AD
|           ---------------------------------------------------
|           Disk:                  disk1
|           Status:                Online
|           Size (Total):          248873222144 B (248.9 GB)
|           Revertible:            Yes (unlock and decryption required)
|           Revert Status:         Reboot required
|           LV Name:               Macintosh HD
|           Volume Name:           Macintosh HD
|           Content Hint:          Apple_HFS
</code></pre>

<p>The most nested entry is the logical volume with a UUID of 4F3C168A-F0BB-40B6-B3FF-CE94D38506AD. Copy that UUID and use it in <code>diskutil cs revert &lt;UUID&gt;</code>:</p>

<pre><code>diskutil cs revert 4F3C168A-F0BB-40B6-B3FF-CE94D38506AD
</code></pre>

<p>Reverting back to a regular volume takes some time, but you can check on the progress by running <code>diskutil cs list</code> until it shows as complete. </p>

<h2 id="step3:rebootthenexpandthepartition">Step 3: Reboot, then expand the partition.</h2>

<p>Your drive is no longer encrypted and doesn't use CoreStorage any more, so you can use Apple's Disk Utility to expand it. The 'partition' section has a pie chart with handles you can drag. Something like this: </p>

<img src="/static/images/blog/2016/diskutility.png" alt="A screenshot of Apple's disk utility, showing the pie chart with handles." />

<h2 id="step4:rebootagainthenconvertyourdrivebacktoacorestoragepartition.">Step 4: Reboot again, then convert your drive back to a CoreStorage partition.</h2>

<p>Run <code>diskutil list</code> to see all the partitions in your Mac. The one you want to convert is probably called &quot;Macintosh HD&quot;. Let's re-enable CoreStorage:</p>

<pre><code>diskutil cs convert &quot;Macintosh HD&quot;
</code></pre>

<h2 id="step5:rebootthenre-enablefilevault">Step 5: Reboot, then re-enable FileVault.</h2>

<p>You can re-enable this from System Preferences &rarr; Security &amp; Privacy &rarr; FileVault. This will also prompt you to reboot, for the last time.</p>

<h2 id="gettingoutoftrouble">Getting out of trouble</h2>

<p>Everything broke with this final reboot. On startup, the Apple logo &amp; a progress bar appeared before being replaced with a &quot;no entry&quot; logo (&#128683;) around &#8532; of the way through. This is <a href="https://support.apple.com/en-ca/HT204156">how a Mac says</a> &quot;I found something that looked like OSX, but didn't contain a valid system folder.&quot; </p>

<p>The short-term fix was to reboot while holding the <key>option &#8997;</key> key. There was only one option (&quot;Macintosh HD&quot;) in the list, which booted fine. The permanent fix was to use &quot;System Preferences&quot; &rarr; &quot;Startup disks&quot; and ensure that &quot;Macintosh HD&quot; was selected.</p>

<div class="footnotes">
<hr>
<ol>

<li id="osxfilevault:1">
<p>This screenshot isn't from my system, so don't worry about the lack of OSX partitions here. It's just to show the unallocated space after the first partition on the drive. <a href="#osxfilevault:1" title="return to article" class="reversefootnote">&nbsp;&#8617;</a></p>
</li>
</ol>
</div>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2016/05/07/expanding-osx-filevault-partitions-on-el-capitan</guid><pubDate>Sat, 07 May 2016 04:35:07 +0100</pubDate></item><item><title>Using structs in Arduino projects</title><link>https://alexpounds.com/blog/2016/01/10/using-structs-in-arduino-projects</link><description><![CDATA[<p>I had some trouble getting structs to work in my <a href="https://arduino.cc">Arduino</a> project. This is how I fixed my code.</p>

<p>My project's ultimate goal is to replace the innards of a <a href="https://www.flickr.com/photos/79694484@N00/4023885869/">fibre optic lamp</a> with a custom lightshow, but it's also a chance to play around with low-level circuitry &amp; coding<a href="#fibrefn:1" id="fibrefnref:1" class="footnote"><sup>1</sup></a>. So far, I've <a href="https://www.instagram.com/p/5UXtLLRr2l/">designed</a> and <a href="https://www.instagram.com/p/7ZTgpKxrzr/">prototyped</a> a hardware LED controller that's driven by an Arduino. The Arduino pumps out binary to the controller; this determines which LEDs light up. </p>

<a href="/static/blog/2016/fibrelights_prototype.jpg">
<img src="/static/blog/2016/fibrelights_prototype.jpg" alt="A close-up of the circuit board" />
</a>

<p>Each of the 4 LEDs you see on the board is an RGB LED, meaning it's actually a package of individual red, green, and blue LEDs. My old code used numbers to choose which colour to display, so it had function signatures like these: </p>

<pre><code>void turnOnLED(int colour, int led);
void bounceColour(int colour); // A 'chase' pattern across all 4 LEDs.
void fadeBetween(int startingColour, int endingColour, int duration); // Fade between two colours in `duration` milliseconds
</code></pre>

<p>That's fine for pure colours, but it doesn't allow for compound colours (mixes of red, green, and blue) because the controller can only turn LEDs on and off. If you want purple, for instance, you turn on the red LED for a few milliseconds, then turn it off &amp; turn blue on for a few milliseconds. Repeat this over &amp; over and persistence of vision does the rest. </p>

<p>I could have used an integer for each colour, but using a struct keeps all the information in a single variable. I also created some constants for common colours using my new struct:</p>

<pre><code>struct Colour {
    byte red;
    byte green;
    byte blue;
};

const Colour C_RED = {1, 0, 0};
const Colour C_BLUE = {1, 0, 1};
const Colour C_PURPLE = {1, 0, 2}; // 2 parts blue to 1 part red.
const Colour C_COLOURS[] = {C_RED, C_BLUE, C_PURPLE};
</code></pre>

<p>Next, I updated my functions to take a <code>Colour</code> parameter instead of an <code>int</code>. I also changed my parameters so they were <a href="https://en.wikipedia.org/wiki/Pointer_(computer_programming)">pointers</a> to the <code>Colour</code> instead; I couldn't get my code to compile without this.</p>

<pre><code id="fibresignatures">void turnOnLED(Colour* colour, int led);
void bounceColour(Colour* colour);
void fadeBetween(Colour* start, Colour* ending, int duration);
</code></pre>

<p>The <code>-&gt;</code> operator is used to access the values from the <code>Colour*</code> arguments<a href="#fibrefn:2" id="fibrefnref:2"><sup>2</sup></a>:</p>

<pre><code>void turnOnLED(Colour* colour, int led) {
    float total_time = 3500;
    float total_colours = colour-&gt;red + colour-&gt;green + colour-&gt;blue;
    float timeRed = total_time * (colour-&gt;red / total_colours);
    float timeGreen = total_time * (colour-&gt;green / total_colours);
    float timeBlue = total_time * (colour-&gt;blue / total_colours);

    // Rest of function that rapidly changes between red, green, and blue removed for brevity.
}
</code></pre>

<p>Now the functions take a pointer to a <code>Colour</code>, I can change the calls to them to pass the address of a colour (using the <code>&amp;</code> operator): </p>

<pre><code>void loop() {
    bounceColour(&amp;C_RED);
    bounceColour(&amp;C_COLOURS[random(0, 3)]);
}
</code></pre>

<p>The final piece of the puzzle is to work around some limitations in the Arduino IDE. The IDE <a href="https://www.arduino.cc/en/Hacking/BuildProcess">preprocesses your code</a> before passing it to the compiler. One of its transformations is to generate function prototypes for your code &ndash; but it doesn't get it right for functions that use custom types, so you have to define them youself. The docs <a href="https://www.arduino.cc/en/Hacking/BuildProcess">recommend you add it to a header file</a>, but if you've only got a few then you can add them directly to your sketch. I added <a href="#fibresignatures">my function signatures</a> below the <code>struct Colour</code> definition.</p>

<p>To summarise: </p>

<ol>
<li>Declare your struct at the top of your file.</li>
<li>Update or override your functions so they take a pointer to your new struct. Remember to use the <code>&amp;</code> operator when calling the new functions!</li>
<li>Add function prototypes immediately after your struct definition for functions that take your struct as a parameter (or return the struct).</li>
<li>Use the <code>-&gt;</code> operator to access the properties in your struct.</li>
</ol>

<h2 id="anasideonunderstandingpointers">An aside on understanding pointers</h2>

<p>Pointers are a straightforward concept &ndash; &quot;a variable that holds the address of a value, rather than holding the value directly,&quot; &ndash; but are really challenging to fully understand and use. </p>

<p>One trick that helped me was pronouncing the <code>*</code> in variable declarations as 'a pointer to'<a href="#fibrefn:3" id="fibrefnref:3"><sup>3</sup></a>, and pronouncing <code>&amp;</code> as &quot;the address of&quot;. So <code>turnOnLED(Colour* colour, int led)</code> is read aloud as &quot;a function turn-on-LED that takes <strong>a pointer to</strong> a Colour and an integer&quot;. Or, consider the call to <code>bounceColour</code> here:</p>

<pre><code>void loop() {
    bounceColour(&amp;C_RED);
}
</code></pre>

<p>I say this as &quot;call bounce-colour, and pass it <strong>the address of</strong> <code>C_RED</code>.&quot;</p>

<p>Another thing that helped was grasping that <code>*</code> means different things in declarations &amp; usage. In declarations, <code>*</code> means &quot;this is a pointer&quot;: </p>

<pre><code>int* avocado; // Define a variable 'avocado' containing a pointer to an integer
</code></pre>

<p>But when using a variables, <code>*</code> means <em>dereference</em>: <em>follow this pointer and use the thing it's pointing at</em>.</p>

<pre><code>// Define a couple of numbers, and a pointer to an integer
int x = 3;
int y = 8;
int* num;
num = &amp;x; // &quot;num equals the address of x&quot;; it's now a pointer to x.
*num = *num + 4; // &quot;Follow num and use the value of what it's pointing to, add 5 to it, and then store it back in the slot pointed to by num.&quot;
</code></pre>

<p>After this code, <code>x</code> is equal to 7, and <code>*num</code> is equal to 7 &ndash; they're both ways to access the same section of memory. <code>std::cout &lt;&lt; num</code> will print the memory address (eg. &quot;0x1234ABCD&quot;); <code>std::cout &lt;&lt; *num</code> will print the value &quot;7&quot;. </p>

<p>This difference is why I write declarations as <code>int* foo</code> (and not <code>int *foo</code>). Keeping the asterisk next to the type emphasises that it's part of the type, not part of the name. <code>foo</code> is a pointer to an integer; there's no variable named <code>*foo</code> in this program. I find it a useful reminder (<a href="http://www.stroustrup.com/bs_faq2.html#whitespace">as does Bjarne Stroustrup</a>), but it can trip you up if you declare multiple variables on one line: </p>

<pre><code>int* bell, book, candle; // Declares one pointer to an int, and 2 ints
int *blinky, inky, clyde; // Also declares one pointer to an int, and 2 ints

int* bell, *book, *candle; // 3 pointers, but looks messy
int *blinky, *inky, *clyde; // Also 3 pointers, with a consistent style
</code></pre>

<p>Personally, I think declaring multiple variables on one line is best avoided. It's hard to tell if it's clever code or a subtle bug with declarations like that. But like all code formatting choices, it's down to individual taste.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fibrefn:1">
<p>There are much better ways to make your own lighting projects if you don't have an interest in the low-level details. <a href="https://www.adafruit.com/category/168">Neopixels</a>, for instance, are reasonably priced, easier to extend, and easier to code for. <a href="#fibrefnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fibrefn:2">
<p><code>-&gt;</code> is used because the argument is a pointer. If we were passing a <code>Colour</code> directly, we'd use the <code>.</code> operator instead (eg. <code>colour.red</code>).  <a href="#fibrefnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fibrefn:3">
<p>I preferred the word 'reference' instead of 'pointer' when I was learning C, but <a href="https://en.wikipedia.org/wiki/Reference_(C%2B%2B)">C++ has a references feature</a> that makes that confusing now. <a href="#fibrefnref:3" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2016/01/10/using-structs-in-arduino-projects</guid><pubDate>Sun, 10 Jan 2016 04:11:47 +0000</pubDate></item><item><title>The Friend Multiplier</title><link>https://alexpounds.com/blog/2015/10/06/the-friend-multiplier</link><description><![CDATA[<p><em>The second in an occasional series about product design heuristics. The <a href="/blog/2014/01/30/products-with-benefits">first article was about mutual benefits</a>.</em></p>

<p>Another heuristic that's useful in product design is something I call &quot;The Friend Multiplier&quot;. There's two parts to it, and both are requirements:</p>

<ol>
<li>Your product must be useful on its own.</li>
<li>Your product must be <em>n</em> times more useful if a user's friends use it too.</li>
</ol>

<p>It has a powerful effect when your product is inordinately more useful (or more compelling, fun, deep, etc) when a user's friends also use it. Done right, it feels like an entirely new dimension opening up: a new world of possibilities, not a couple of new features<sup><a href="#tfmfn:1" id="tfmfnref:1" >1</a></sup>. It's important that the benefits are genuine (there's nothing magical about an artificial barrier of &quot;Wait 4 hours, or invite 5 friends to continue&quot;), and that the friends are a user's real friends<sup><a href="#tfmfn:2" id="tfmfnref:2">2</a></sup> &ndash; people who would have a coffee with your user, given the chance. </p>

<p>But don't overlook the first part: few products can get away with being useless for solo users. Users are more likely to stick around if it's easy for them to start using your product<sup><a href="#tfmfn:3" id="tfmfnref:3">3</a></sup>, and everybody wants to try something before recommending it to their friends. And what if they're not your ideal user? What if they don't live in a big city, or lack early-adopter friends? What if they've got a 4 year old phone or a 10 year old laptop? Will your product still work well for them? Millions of people fall into this demographic and they're often neglected, especially by tech startups. They might not be your primary audience, but if you improve their experience then your product will be better for everybody. </p>

<p>But the multiplier is the magic part; the reason this heuristic indicates your product is on-track, and that word-of-mouth growth is plausible.</p>

<h2>Some examples of friend multiplier magic</h2>

<p>I really like <a href="http://foursquare.com/">FourSquare</a> as an example of the friend multiplier, despite their recent disoriented product decisions. You use FourSquare to log where you've been<sup><a href="#tfmfn:4" id="tfmfnref:4">4</a></sup> and it recommends new places to you. That's mildly useful &amp; fun on its own, but the day FourSquare really clicked for me is burnt into my brain. I was in a caf&eacute; that I'd never visited before and I checked in on FourSquare. FourSquare popped up a 2-year-old note from a friend, giving me the wifi password. Magical! My friend hadn't left it for me; it was a generic tip. But FourSquare knew we were friends, and knew that my friend had left a note here, so it showed me the note when I checked in. There's no wizardry in the technology powering it, but the effect was profound. I was now aware of hidden traces left by my friends; traces I could stumble upon, seek out, or leave for others.</p>

<p><a href="http://www.livejournal.com/">LiveJournal</a> is a simpler example. LiveJournal users post diary entries to the web, either publicly or privately. Which is useful in itself, if you want to keep a diary. But when your friends are on LiveJournal too, you get an intimate window into their lives. LJ's fine-grained privacy settings mean your friends have control over what they're sharing &ndash; but you'll know more about how they feel, what's on their mind, and what they're doing. I never had a LiveJournal, but a lot of my university friends did. I always had a sense that there was an <em>in</em> circle &ndash; a deeper, mutually supportive, more emotionally bonded group &ndash; that I was outside of. Again, there was no groundbreaking technology involved. But the social impact on individuals was huge.</p>

<h2>It won't last forever</h2>

<p>It's important to have a target number in mind for your ideal user's friends. The magical feeling normally ebbs away after a (normally low) threshold. <a href="http://twitter.com/">Twitter</a>'s a rare example with a high threshold: it's better when you follow a few hundred people. Most products have more in common with a shared calendar; more than a handful of people using one results in a deluge of events, making it hard to find ones relevant to you &amp; making the calendar feel like a mess. So pick a low number &amp; design with that number in mind.</p>

<h2>Some counterexamples</h2>

<p>This heuristic isn't a law. Lots of products thrive without any kind of social features, and (<a href="/blog/2014/01/30/products-with-benefits">as before</a>) there's lots of products where it's best avoided. Sometimes that's immediately apparent: I don't want my friends involved in my banking or my to-do list. I think that it's best to keep them away from dating &amp; relationships, too; Tinder's &quot;friends you have in common&quot; feature always felt like a warning about potential future awkwardness, rather than an endorsement.</p>

<p>There's also fuzzier cases. Features that seem like a good idea can fall apart like wet cake once the complications of real life get involved. Windows 10 has a feature where your friends can <a href="http://krebsonsecurity.com/2015/07/windows-10-shares-your-wi-fi-with-contacts/">log on automatically to your wifi</a>. Which sounds great &ndash; your computer already knows who your friends are, so why not let them onto your wifi without having to ask for the password? Ah, but the details: your computer doesn't know about your <em>friends</em>. It knows about your <em>contacts</em>. Contacts contain friends, family, colleagues, ex-lovers, stalkers, businesses, abusers, toxic people you've cut out of your life. A whole lot of people you'd want kept away from your wifi network.</p>

<hr>

<p>The friend multiplier is a simple but effective guideline. It's not a requirement &ndash; if it doesn't make sense for your product, don't worry about it. But in an increasingly connected world, it makes sense to think about how that can make your products much more compelling.</p>

<div class="footnotes">
<hr />
<ol>

<li id="tfmfn:1">
<p>A &quot;solo&quot; vs &quot;with friends&quot; feature comparison would be missing the point, anyway: product design is about what your product lets users accomplish, not the bullet points you can list. <a href="#tfmfnref:1" title="return to article">&#160;&#8617;</a></p>
</li>

<li id="tfmfn:2">
<p>&quot;Real&quot; isn't the same as &quot;real life&quot;; internet-only friends count for this too. It's about genuine, two-way friendships &ndash; not people followed because a user likes their jokes, or stuff they make. <a href="#tfmfnref:2" title="return to article">&#160;&#8617;</a></p>
</li>

<li id="tfmfn:3">
<p>Or service &ndash; <em>especially</em> services. If it's easy for someone to start using your service it's more likely they'll find value in it, so it's less likely they'll cancel. Fewer cancellations mean a lower churn rate, and a lower churn rate makes it easier to build a viable business. <a href="#tfmfnref:3" title="return to article">&#160;&#8617;</a></p>
</li>

<li id="tfmfn:4">
<p>Which is interesting in itself; &quot;Wow, have I really not been here for a year and a half? Really?&quot; <a href="#tfmfnref:4" title="return to article">&#160;&#8617;</a></p>
</li>

</ol>
</div>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2015/10/06/the-friend-multiplier</guid><pubDate>Tue, 06 Oct 2015 06:12:09 +0100</pubDate></item><item><title>Why your multipart emails show up as plaintext</title><link>https://alexpounds.com/blog/2014/09/30/why-your-multipart-emails-show-up-as-plaintext</link><description><![CDATA[<p>While building <a href="http://electrichandshakes.com/">Electric Handshakes</a>, a tool that connects job-hunters to employers via email, I spent days debugging an email problem. My code sent valid multipart emails &ndash; emails with both HTML and plaintext parts &ndash; but Gmail and Mail.app showed the plaintext. Why?</p>

<p>I found my answer <a href="http://tools.ietf.org/html/rfc1341#page-35">buried on page 35 of an RFC</a><a href="#emailfn:1" id="emailfnref:1" ><sup>1</sup></a><a href="#emailfn:2" id="emailfnref:2"><sup>2</sup></a>. <strong>The order of the parts matters. Later parts override earlier ones.</strong> Your mail client will display the final part it understands. I&#8217;d placed my plaintext version <em>after</em> the HTML version. Swapping those sections fixed the problem. </p>

<p>Other common causes of errors include: </p>

<ul>
<li><strong>Sending an invalid multipart message</strong>. There&#8217;s a few <a href="http://www.mimevalidator.net/">online</a> <a href="http://tools.ietf.org/tools/msglint/">validators</a>. Both of these declared my message to be invalid, but didn&#8217;t point out the ordering error above.

<ul>
<li>In particular, make sure you send a valid <code>Content-Type</code> header. The capitalisation matters, and the value should be <code>multipart/alternative</code>.</li>
</ul></li>
<li><strong>Sending invalid HTML</strong>. I expected a complete HTML document would be required - one with <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code> tags rather than just formatting. But there isn&#8217;t consensus on that. Microsoft Outlook sends full HTML documents, as does Yahoo Mail, Hotmail, and Apple&#8217;s Mail.app. But Gmail sends formatting only, with no document structure. I think such an email is <em>technically</em> invalid<a href="#emailfn:3" id="emailfnref:3"><sup>3</sup></a>, but every mail client renders it anyway. Gmail can send &amp; store smaller emails by omitting the document structure.

<ul>
<li>Even without a fully-structured document, markup errors can still prevent your message from being displayed. Make sure all your tags are closed, you&#8217;ve closed them in the right order, and so on.</li>
</ul></li>
</ul>

<p>If you&#8217;re using Rails, you can take some email pain away by using <a href="https://github.com/ryanb/letter_opener">the <code>letter_opener</code> gem</a> to preview your mails in your browser, and <a href="https://github.com/fphilipe/premailer-rails">the <code>premailer-rails</code> gem</a> to inline your CSS. It can also generate your plaintext parts automatically, and generally does a decent job of it. </p>

<div class="footnotes">
<hr />
<ol>

<li id="emailfn:1">
<p>&#8220;In general, user agents that compose multipart/alternative entities should place the body parts in increasing order of preference, that is, with the preferred format last. For fancy text, the sending user agent should put the plainest format first and the richest format last. Receiving user agents should pick and display the last format they are capable of displaying.&#8221; <a href="#fnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="emailfn:2">
<p>When you find yourself on page 35 of a standards document praying for answers, your day&#8217;s already blown.</li>
<li id="emailfn:3">It&#8217;s invalid because the HTML part is declared as <code>text/html</code>, and you need the structural tags for your document to be valid HTML. <a href="#fnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>

]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2014/09/30/why-your-multipart-emails-show-up-as-plaintext</guid><pubDate>Tue, 30 Sep 2014 23:59:39 +0100</pubDate></item><item><title>Don't call it magic</title><link>https://alexpounds.com/blog/2014/07/31/dont-call-it-magic</link><description><![CDATA[<p>I recently wrapped up 6 months of teaching at <a href="http://generalassemb.ly/">General Assembly</a>. I was teaching <abbr title="Web Development Immersive">WDI</abbr> - a 12 week course that turns beginner programmers into employable junior web developers. It taught me a lot about teaching. One subtle thing I picked up is that we shouldn't talk about magic when we talk to novices. </p>

<p>Novice programmers like to ask questions, but those questions can't always be answered immediately. Either the explanation would be too confusing, or take up too much time, or be a useless distraction. So when the beginner asks, &quot;But <em>how</em> did it know to do that?&quot; we reply &quot;Magic.&quot; We say &quot;Magic&quot; because developer culture is tied up with D&amp;D, fantasy novels, and the idea that programmers are mystical and inscrutable. But what we really mean is &quot;Don't worry about it.&quot; Rails isn't actually magic. You know that. I know that. The novices know that too<sup><a href="#magicfn:1" id="magicfnref:1">1</a></sup>.</p>

<p>But the beginners don't always hear &quot;Don't worry about it right now.&quot; Sometimes, they hear &quot;It's beyond everybody's understanding, and we're all OK with that.&quot; These brackets and semicolons are confusing to everyone. Just repeat it back phonetically and everything will be fine. You can fix your bugs via trial &amp; error. Nobody understands it anyway. </p>

<p>And that's a dangerous untruth. Programming is entirely understandable: every line, every word, every symbol. Some of the most productive teaching sessions have come from not allowing a student to handwave past some code and insisting they explain how it works, atom by atom. What's this line do? It assigns something to a variable. What's in that variable - what's its type? OK, what did we set it to? That second half, after the plus - what's it doing? Good. Next line. </p>

<p>One half of an instructor's role is imparting knowledge &amp; understanding. The knowledge will come in time if you immerse the students in it, but the understanding will be slower to arrive if students aren't looking out for it. There's a difference between &quot;We don't have to look behind the curtain right now,&quot; and &quot;The Wizard is real&quot;. the language teachers use should reflect that.</p>

<p>The other half of the job is instilling confidence &amp; self-belief. Programming is hard, technical, confusing work. It gnaws at almost everyone. You have to reinforce that yes, the students <em>are</em> programmers. What they are doing <em>is</em> programming - no matter how much they have to Google for answers and ask for help.</p>

<p>Again, the language you use can reinforce this message. It's better to ask a student &quot;What do you know about <em>[subject]</em>?&quot; instead of &quot;Do you know about <em>[subject]</em>?&quot;. The former question is an open-ended chance for the student to show off their knowledge. The latter is often heard as &quot;I have set an arbitrary high standard for your knowledge about <em>[subject]</em>. Do you dare assert that you meet it?&quot;. Beginners will always say &quot;No,&quot; even if they have encountered it before. You'll quickly find out they do know about <em>[subject]</em><sup><a href="#magicfn:2" id="magicfnref:2">2</a></sup>, but it's still a tiny drag-down instead of a tiny build-up. You can't give people a giant boulder of confidence in one go. You can only give them tiny grains of positive feedback, and trust that one day it will outweigh their self-doubt. </p>

<div class="footnotes">
<hr />
<ol>

<li id="magicfn:1">
<p>The Ruby source code <a href="https://github.com/ruby/ruby/blob/aa3b5062707b72189b42a912dc6df58ab3bb68f8/dir.c#L1232">might not know that</a>. <a href="#magicfnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="magicfn:2">
<p>&quot;Okay, the thing about frobbing the whatsit is...&quot; &quot;Oh, I know about that, I used that last week.&quot; <a href="#magicfnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2014/07/31/dont-call-it-magic</guid><pubDate>Thu, 31 Jul 2014 23:57:43 +0100</pubDate></item><item><title>The Vimrc Antiques Roadshow</title><link>https://alexpounds.com/blog/2014/06/06/the-vimrc-antiques-roadshow</link><description><![CDATA[<p>Last week, I gave a talk at <a href="http:///www.meetup.com/Vim-London/">Vim London</a> about Vim's configuration file. We examined <a href="http://ethicsgirls.com/stuff/.vimrc">my .vimrc</a>, <a href="https://github.com/nicwest/.dotfiles/blob/9af388c2e57f7261e32230ab474997d02659ebb3/vim/.vimrc">Nic West's</a>, <a href="https://github.com/timmow/vimrc/blob/master/_vimrc">Tim Mower's</a>, <a href="https://github.com/arturoherrero/dotfiles/blob/master/.vimrc">Arturo Herrero's</a>, <a href="https://github.com/jamescooke/vi-config/blob/master/.vimrc">James Cooke's</a>, and <a href="https://github.com/Wolfy87/dotfiles/blob/19ebff85a081c735567c6ea6f313f7a75277dc74/vim/config.vim">Oliver Caldwell's</a>. We also had a look at <a href="https://github.com/nelstrom/dotfiles/blob/master/vimrc">Drew Neil's</a> during the Q&amp;A.</p>

<p><iframe src="//player.vimeo.com/video/96886790?title=0&amp;byline=0" width="580" height="326" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></p>

<h2 id="thebasics">The basics</h2>

<p>Vim reads a configuration file called <code>~/.vimrc</code> when it starts. You don't have to keep all your configuration in one file; several people put settings in other files (such as <code>~/.vim/bundle</code>) and add <code>source ~/.vim/bundle</code> to their <code>.vimrc</code>. You can run <code>vim -u filename</code> to read a different settings file; nobody at the meeting used that, but some people use it to manage different settings across projects. You can do this automatically with <code><a href="http://vimdoc.sourceforge.net/htmldoc/options.html#%27exrc%27">set exrc</a></code> and <code><a href="http://vimdoc.sourceforge.net/htmldoc/options.html#%27secure%27`">set secure</a></code>.</p>

<h2 id="goodhabits">Good habits</h2>

<ul>
<li>Add a comment with a URL when copying settings to your <code>.vimrc</code> from an online article.</li>
<li>Don't be afraid to <a href="http://ajh17.github.io/2014/05/25/can-someone-help-me/index.html">ask Vim for :help</a>.</li>
<li>Keep your <code>.vimrc</code> in source control. As well as keeping track of what you add and remove, it makes it easier to keep your files in sync between several different machines (such as home &amp; work).</li>
<li>Bind your most used commands to the <key>F<em>x</em></key> keys; they're unused in Vim, so are free for your own use.</li>
<li>Use a tool to manage your Vim plugins; <a href="https://github.com/gmarik/Vundle.vim">Vundle</a> is preferable to <a href="https://github.com/tpope/vim-pathogen/">Pathogen</a> because it saves you from the horrible world of Git submodules.</li>
<li>Remember that Github won't show non-printable characters, so if you're browsing <code>.vimrc</code>s you might miss important details.</li>
</ul>

<h2 id="modernisingvimmakingitmoresensible">Modernising vim &amp; making it more sensible</h2>

<p>Most <code>.vimrc</code>s contain some settings to smooth over some foibles and legacy features: </p>

<ul>
<li><code>set nocompatible</code> tells Vim to forget about Vi compatibility. Interestingly, as soon as you create a <code>~/.vimrc</code> this option <a href="http://vimdoc.sourceforge.net/htmldoc/starting.html#compatible-default">gets set automatically</a>.</li>
<li><code>set hidden</code> allows for hidden buffers - basically stopping Vim whining when you open more than one file.</li>
<li><code>set ttyfast</code> <a href="http://vimdoc.sourceforge.net/htmldoc/options.html#%27ttyfast%27">might also be on by default</a>, depending on your <code>$TERM</code> environment variable. When on, Vim will update your screen in bigger batches.</li>
<li><code>set backspace=indent,eol,start</code> enables backspacing over everything, like every modern editor ever.</li>
<li><code>nmap j gj</code> and <code>nmap k gk</code> make <key>j</key>/<key>k</key> move the cursor up/down by lines on the screen, not lines in the file. Navigation feels more natural when using word wrap this way.</li>
<li><code>au BufRead,BufNewFile *.md set filetype=markdown</code> sets <code>foo.md</code> files to be Markdown, not Modula2.</li>
<li>You can get <a href="http://vimdoc.sourceforge.net/htmldoc/options.html#%27wildmenu%27">better tab completion for Vim commands</a> if you <code>set wildmenu</code>. You may also like to <code>set wildmode=list:longest</code>, and you can ignore certain files - like Python compiled files - with <code>set wildignore=*.pyc</code>.</li>
<li>You can set a mark in Vim with <key>m</key><key>a</key>, and jump back to that <em>line</em> with <key>'</key><key>a</key>. If you want to back to that exact cursor position, you can use <key>`</key><key>a</key>, but that's harder to press. You can swap <key>`</key> and <key>'</key> with <code>nnoremap ' `</code> and <code>nnoremap ` '</code>.</li>
<li>Normally Vim will scroll the screen when the cursor hits the first/last line. You can make it scroll 3 lines earlier with <code>set scrolloff=3</code>. Nic went as far as to <code>set scrolloff=15</code>.</li>
</ul>

<h2 id="viewssessions">Views &amp; Sessions</h2>

<p>Vim supports views, which save the cursor position &amp; code folds between editing sessions (along with a <a href="http://vimdoc.sourceforge.net/htmldoc/starting.html#:mkview">few other settings</a>). I've used an <a href="http://vimdoc.sourceforge.net/htmldoc/autocmd.html#autocommand">autocommand</a> to automatically save and load a view whenever I edit a file: </p>

<pre><code>au BufWinLeave ?* silent mkview
au BufWinEnter ?* silent loadview
</code></pre>

<p>Vim also has a <a href="http://vimdoc.sourceforge.net/htmldoc/starting.html#Session">sessions feature</a>, which saves the whole editing session - everything in the views, along with the open buffers, window layout, tabs, etc. Oliver has bound <key>F7</key> and <key>F8</key> to save/load a session: </p>

<pre><code>nnoremap &lt;F7&gt; :mksession! .quicksave.vim&lt;CR&gt;
nnoremap &lt;F8&gt; :source .quicksave.vim&lt;CR&gt;
</code></pre>

<p>I recommended he move them to non-neighbouring keys, to make it harder to accidentally hit the wrong key &amp; save an empty session.</p>

<h2 id="pluginsandothertools">Plugins and other tools</h2>

<p>The most interesting plugins were: </p>

<ul>
<li><a href="https://github.com/kien/ctrlp.vim">CtrlP</a>, a fuzzy-finder for navigating projects.</li>
<li><a href="https://github.com/tpope/vim-endwise">Vim-endwise</a>, to add <code>end</code> automatically in Ruby.</li>
<li><a href="https://github.com/jeffkreeftmeijer/vim-numbertoggle">Vim-numbertoggle</a> will show you relative line numbers in normal mode and absolute line numbers in insert mode. This makes it easier to write multiple line-spanning motions. You can use <code>set number</code> to always show line numbers and <code>set relativenumber</code> to always show relative numbers.</li>
<li><a href="https://github.com/tpope/vim-unimpaired">Vim-unimpaired</a> adds some navigation commands to the <key>[</key><key>]</key> keys.</li>
<li><a href="https://github.com/Lokaltog/vim-easymotion">Easymotion</a> turns motions into a multiple-choice option.</li>
</ul>

<p>Some tools that people use with Vim include:</p>

<ul>
<li><p><a href="http://beyondgrep.com/">Ack</a> (and the similar <a href="http://geoff.greer.fm/2011/12/27/the-silver-searcher-better-than-ack/">Ag</a>, AKA &quot;The Silver Searcher&quot;). They're <code>grep</code>-like tools that have useful features like respecting your <code>.gitignore</code> file. You can tell Vim to use <code>ag</code> for its <a href="http://vimdoc.sourceforge.net/htmldoc/quickfix.html#grep">built-in grep</a>, as well as telling CtrlP to use it too: </p>

<pre><code>if executable('ag')
  set grepprg=ag\ --nogroup\ --nocolor
  let g:ctrlp_user_command = 'ag %s -l --nocolor -g &quot;&quot;'
endif
</code></pre></li>
<li><p><a href="http://www.kuro5hin.org/story/2004/3/9/16838/14935">Screen</a> and <a href="http://tmux.sourceforge.net/">tmux</a> remain popular. Plugins like <a href="https://github.com/christoomey/vim-tmux-navigator">vim-tmux-navigator</a> and <a href="edkolev/tmuxline.vim">tmuxline</a> provide some Vim integration. </p></li>
<li><p><a href="http://git-scm.com/">Git</a> is used by everyone for source control, often with the <a href="https://github.com/tpope/vim-fugitive">vim-fugitive</a> plugin.</p></li>
</ul>

<h2 id="searchandsearchhighlighting">Search and search highlighting</h2>

<p>Vim can highlight search results as you type: </p>

<pre><code>set hlsearch
set incsearch
</code></pre>

<p><code>set ignorecase</code> makes searching case insensitive; <code>set smartcase</code> makes searching case insensitive unless you use any capital letters. If you find yourself using <a href="http://vim.wikia.com/wiki/Search_and_replace">substitutions</a> a lot then you might want to <code>set gdefault</code> to make replacement global without having to add the <code>g</code> flag.</p>

<h2 id="refreshing">Refreshing</h2>

<p>I've found that Vim sometimes messes up syntax highlighting or forgets the filetype. I've bound <key>F5</key> to refresh highlighting and filetype detection: </p>

<pre><code>noremap &lt;F5&gt; &lt;esc&gt;:syntax sync fromstart&lt;cr&gt;:filetype detect&lt;cr&gt;
inoremap &lt;F5&gt; &lt;esc&gt;:syntax sync fromstart&lt;cr&gt;:filetype detect&lt;cr&gt;a
</code></pre>

<p>Oliver used his <key>F5</key> key to regenerate his <a href="http://en.wikipedia.org/wiki/Ctags">ctags</a>:</p>

<pre><code>command! GenerateTags call system('ctags -Rf ./.tags --python-kinds=-i --exclude=.git `cat .srclist`') | echo
nnoremap &lt;F5&gt; :GenerateTags&lt;CR&gt;
</code></pre>

<p>You could combine these if you wanted to.</p>

<h2 id="swapfilesbackupsandundo">Swapfiles, backups, and undo</h2>

<p>Vim can create <a href="http://vimdoc.sourceforge.net/htmldoc/editing.html#backup">backups</a> when you write files, <a href="http://vimdoc.sourceforge.net/htmldoc/undo.html#undo-persistence">save your undo history between sessions</a>, and uses a <a href="http://vimdoc.sourceforge.net/htmldoc/recover.html#swap-file">swap file</a> to track changes when running. </p>

<p>Just about everybody tells Vim to put these files in their own directories. At the very least, you won't have to add them to your <code>.gitignore</code> files that way: </p>

<pre><code>set undodir=~/.vim/tmp/undo/
set backupdir=~/.vim/tmp/backup/
set directory=~/.vim/tmp/swap/
</code></pre>

<p>It seems like a good idea to make those directories if they don't already exist: </p>

<pre><code>if !isdirectory(expand(&amp;undodir))
  call mkdir(expand(&amp;undodir), &quot;p&quot;)
endif
if !isdirectory(expand(&amp;backupdir))
  call mkdir(expand(&amp;backupdir), &quot;p&quot;)
endif
if !isdirectory(expand(&amp;directory))
  call mkdir(expand(&amp;directory), &quot;p&quot;)
endif
</code></pre>

<p>Turn on persistent undo with <code>set undofile</code>. Turn backups on with <code>set backup</code>. Some people turn off swapfiles with <code>set noswapfile</code>; Vim speeds up, but you're promising that Vim will always shut down cleanly &amp; you'll never open the same file in two different Vim instances. </p>

<h2 id="avoidingtheescapekeyandotherpersonaltasteissues">Avoiding the escape key, and other personal taste issues</h2>

<p>Some people like to avoid the escape key, and use keystrokes like <key>j</key><key>j</key> and <key>j</key><key>k</key> instead. Tim forced himself to learn this by remapping his <key>Esc</key> to a no-op:</p>

<pre><code>noremap &lt;Esc&gt; &lt;Nop&gt;
inoremap jk &lt;Esc&gt;
inoremap jj &lt;Nop&gt;
</code></pre>

<p>We also mentioned the influence of the <a href="http://en.wikipedia.org/wiki/ADM-3A">ADM-3A</a>, a common terminal used when Vi was written. Its <key>Escape</key> was located where modern <key>Tab</key> keys are and its tilde key was labelled &quot;Home&quot;. This led to the use of <code>~</code> as a shortcut for the home directory. It also had arrows on <key>h</key>, <key>j</key>, <key>k</key>, and <key>l</key> - which is why they're used for navigation in Vim and other programs. </p>

<p>James' <code>.vimrc</code> swapped <code>:</code> for <code>;</code>, to cut down on <key>shift</key> usage: </p>

<pre><code>nnoremap ; :
nnoremap : ;
</code></pre>

<p>But James recommended against this, as when he uses other programs with Vim mappings his muscle memory is basically useless. </p>

<h2 id="obeyingcodingconventions">Obeying coding conventions</h2>

<p>If your coding style guide specifies a maximum line length, you can <code>set colorcolumn=80</code> to add a stripe at the 80 column mark. </p>

<p>You can show hidden characters (like trailing whitespace and tabs) with custom symbols. Here's James': </p>

<pre><code>set list 
set listchars=eol:&#4294967295;,tab:&#9655;\ ,
</code></pre>

<p>Shortcuts for stripping trailing whitespace were also popular: <code>nnoremap &lt;F2&gt; :%s/\s\+$//e&lt;CR&gt;</code></p>

<h2 id="micro-optimisations">Micro-optimisations</h2>

<p>If you find yourself performing a repetitive task, it's worth finding a way to optimise it. Nic <a href="https://github.com/nicwest/.dotfiles/blob/9af388c2e57f7261e32230ab474997d02659ebb3/vim/.vimrc#L283-L311">wrote a function that copies a path to his clipboard</a>, so he could paste it easily into a VM. Tim had a snippet that <code>var_dump()</code>s the variable under the cursor (a PHP way of printing out variables for debugging): <code>nmap dvd viwy&lt;Esc&gt;odie(var_dump());&lt;Esc&gt;hhP</code></p>

<p>James likes to use <key>Ctrl</key>+<key>j</key> as a shortcut for <code>:tabedit</code>:</p>

<pre><code>nnoremap &lt;C-j&gt; :tabe</code></pre>

<p>The trailing space is important so you can start typing the filename immediately. </p>

<p>Oliver bound <a href="http://usevim.com/2012/07/20/vim101-leader/">leader</a> <key>z</key> to replace the misspelling under the cursor with the first suggested fix: <code>nnoremap &lt;leader&gt;z 1z=</code></p>

<p>Arturo added a mapping for <code>:w!!</code> to save the current file via <code>sudo</code>:</p>

<pre><code>cmap w!! %!sudo tee &gt; /dev/null %</code></pre>

<h2 id="highlightwordsyouwanttoavoid">Highlight words you want to avoid</h2>

<p>It's good practice to avoid words like &quot;obviously&quot;, &quot;just&quot;, &amp; &quot;simply&quot; when writing educational articles. You can <a href="http://ajh17.github.io/2014/05/25/can-someone-help-me/index.html">use a custom highlighter</a> to make them stand out. </p>

<h2 id="miscellaneous">Miscellaneous</h2>

<ul>
<li><code>set matchtime=2</code> determines how long Vim will highlight matching brackets, in tenths of a second.</li>
<li>You can use <a href="http://vimdoc.sourceforge.net/htmldoc/usr_28.html">vim folds</a> to hide code in long files by &quot;folding&quot; it up into one line.</li>
<li><a href="https://github.com/search?q=%22%3Awq%22&amp;ref=cmdform&amp;type=Code">Searching Github for ':wq' gives 7.1 million results.</a></li>
<li><code>set autoread</code> will reload the file if it changes. <a href="http://www.mail-archive.com/vim@vim.org/msg05900.html">It's not <code>tail -f</code></a>, though: you have to run a shell command or invoke <code>:checktime</code> to make Vim re-check the file.</li>
<li>James recommended <a href="http://vimeo.com/65250028">Bare-bones navigation</a>, a previous talk by Kris Jenkins.</li>
<li>Oliver had an <a href="https://github.com/Wolfy87/dotfiles/blob/19ebff85a081c735567c6ea6f313f7a75277dc74/vim/config.vim#L49-L60">embedded Python program in his <code>.vimrc</code></a> to automatically set up his <a href="http://docs.python-guide.org/en/latest/dev/virtualenvs/"><code>virtualenv</code></a>. I'd keep this in a dedicated script and call it from the <code>.vimrc</code> instead.</li>
<li><code>set nostartofline</code> <a href="http://vimdoc.sourceforge.net/htmldoc/options.html#%27startofline%27">keeps the cursor in place</a> when you re-indent code. Sadly, this doesn't move the cursor with the indent so it's not as useful as it sounds.</li>
<li><key>z</key><key>z</key> moves the line under the cursor to the middle of the screen, which is useful when coding in front of an audience. <key>z</key><key>t</key> moves the current line to the top. You can also use <code>set cursorline</code> to underline the current line, which can also help an audience follow along (or a presenter to follow their notes).</li>
<li><a href="http://blog.carbonfive.com/2011/10/17/vim-text-objects-the-definitive-guide/">Text objects</a> are awesome and you should definitely learn them.</li>
</ul>

<h2 id="themysteriouspinkpingpongballs">The mysterious pink ping pong balls</h2>

<p>After the talk, Tim wrote in about the <key>Ctrl</key> + <key>l</key> mapping we failed to decipher. He had some bugfixes and an explanation: <code>inoremap &lt;C-R&gt; @@@&lt;Esc&gt;hhkywjl?@@@&lt;CR&gt;P/@@@&lt;CR&gt;3s</code> lets you use <key>Ctrl</key> + <key>r</key> to copy the previous line word-by-word.</p>

<hr />

<p>Thanks to Drew for organising <a href="http://www.meetup.com/Vim-London/">Vim London</a> and to Skimlinks for hosting the meetup.</p>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2014/06/06/the-vimrc-antiques-roadshow</guid><pubDate>Fri, 06 Jun 2014 17:18:08 +0100</pubDate></item><item><title>How to customise rotating wallpapers on Ubuntu 13.10</title><link>https://alexpounds.com/blog/2014/04/25/how-to-customise-rotating-wallapers-on-ubuntu</link><description><![CDATA[<p>Ubuntu has a nice selection of wallpapers that change throughout the day. But there were a couple that I didn't like, and the GUI doesn't have a way to customise the selection. Here's how I got rid of the images I disliked and added my own to the rotation.

<p>The photos are kept in <code>/usr/share/backgrounds/</code>. This directory turned out to contain a bunch of pretty pictures I'd never seen before &mdash; each version upgrade brings a new set, but they're not included in the rotation automatically. There's also no GUI to flip through a set of images throughout the day; you must create a couple of XML files instead. I followed these steps: </p>

<ol>
<li>Delete any images you don't want from <code>/usr/share/backgrounds</code>.</li>
<li>Create a directory for your custom XML files:<br />
 <code>mkdir ~/.local/share/gnome-background-properties; cd ~/.local/share/gnome-background-properties</code></li>
<li>Create an XML file that describes a slideshow. I <a href="https://gist.github.com/creature/11101265">wrote some Ruby</a> to generate the file; you can run it like this:
<p><code>ruby generator.rb /usr/share/backgrounds/*.jpg &gt; mywallpapers.xml</code></p>
 If you've got other files you'd like to include, you can include them as extra arguments before the <code>&gt;</code>:
<p><code>ruby generator.rb /usr/share/backgrounds/*.jpg /home/alex/wallpapers/*.jpg &gt; mywallpapers.xml</code></p>
 If you'd like to create the files by hand, you're mad, but here are the rules:<p>
  <ul>
<li>It should have a <code>&lt;starttime&gt;</code> element with a date in the past.</li>
<li>It should have pairs of <code>&lt;static&gt;</code> and <code>&lt;transition&gt;</code> elements. The <code>&lt;static&gt;</code> element displays a wallpaper for the set time; the <code>&lt;transition&gt;</code> element crossfades it to the next one. The duration is given in seconds, so each wallpaper displays for 30 minutes.</li>
<li>The last element should transition back to the first. This makes the slideshow loop forever.</li></ul></p></li>

<li>Create an XML file <code>mywallpaperlist.xml</code> to show your new wallpapers in the appearance properties. Don't forget to change the <code>&lt;filename&gt;</code> property to contain your own home directory. You can use <code>pwd</code> from the terminal to show it if you don't know the correct path.
<p><pre>
&lt;!DOCTYPE wallpapers SYSTEM &quot;gnome-wp-list.dtd&quot;&gt;
&lt;wallpapers&gt;
  &lt;wallpaper deleted=&quot;false&quot;&gt;
&lt;name&gt;My Wallpapers&lt;/name&gt;
&lt;filename&gt;/home/alex/.local/share/gnome-background-properties/mywallpapers.xml&lt;/filename&gt;
&lt;options&gt;zoom&lt;/options&gt;
&lt;pcolor&gt;#2c001e&lt;/pcolor&gt;
&lt;scolor&gt;#2c001e&lt;/scolor&gt;
&lt;shade_type&gt;solid&lt;/shade_type&gt;
  &lt;/wallpaper&gt;
&lt;/wallpapers&gt;
</pre></p></li>
</ol>

<p>That's it! I didn't have to restart Unity, or jump through any other hoops. If your files are readable and valid XML, then your wallpaper pack should show up if you reopen the appearance properties. </p>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2014/04/25/how-to-customise-rotating-wallapers-on-ubuntu</guid><pubDate>Fri, 25 Apr 2014 17:49:32 +0100</pubDate></item><item><title>Burn Facebook to the ground</title><link>https://alexpounds.com/blog/2014/04/08/burn-facebook-to-the-ground</link><description><![CDATA[<p><em>AKA &quot;A tale of two share widgets&quot;.</em></p>

<p>I recently built <a href="http://ethicsgirls.com/how-many-shipping-forecast-areas-can-you-name/">an internet toy</a>. A big part of the toy is social sharing; I wanted players to tell their friends their scores. Most people use Twitter or Facebook, so sharing to those services should be as simple as possible.</p>

<p>A &quot;Share your score on Twitter&quot; button took me about 5 minutes. <a href="https://dev.twitter.com/docs/intents#tweet-intent">It's just a link</a>. Customise a couple of parameters and you're good to go. Tumblr's <a href="http://www.tumblr.com/buttons">just as easy</a>. You have to click through a few options to see an example, but it's also just a link. But Facebook... oh, Facebook. </p>

<p>Facebook's sharing process is shamefully convoluted. If you <em>just</em> want to share a URL, you can <a href="https://developers.facebook.com/docs/plugins/share-button/#faqdialog">use a straightforward hyperlink</a>, though it will discourage you<sup><a href="#fbfn:1" id="fbfnref:1">1</a></sup>. But if you want to share a URL <em>with a customised description</em> &ndash; something Twitter and Tumblr managed with a simple link &ndash; here's what you have to do: </p>

<ol>
<li>Create a developer account.</li>
<li>Create a new app.</li>
<li>Get that app approved &amp; available to the public.</li>
<li>Include Facebook's JavaScript in your own page<sup><a href="#fbfn:2" id="fbfnref:2">2</a></sup>.</li>
<li>Include an empty div in your page for Facebook's JavaScript to use.</li>
<li>Make a call to <code>FB.ui</code> with the relevant details.</li>
</ol>

<p>And to top it all off you're now maintaining that code forever, because Facebook's API thrashes around like a ferret on a leash. <a href="https://developers.facebook.com/bugs/252983554810810/">The Share button is deprecated</a>! No, the <a href="https://developers.facebook.com/docs/plugins/share-button">Share button is supported</a>! But you should use the <a href="https://developers.facebook.com/docs/reference/dialogs/feed">JavaScript Feed Dialog</a>! There's also a <a href="https://developers.facebook.com/docs/reference/dialogs/feed#redirect">URL redirection method</a>, hidden away with a minimum of documentation (and still requiring an App ID). And the <a href="https://developers.facebook.com/x/bugs/357750474364812/">format might change</a>, so make sure you're reading Facebook bug reports! But good luck finding them, as <a href="https://developers.facebook.com/robots.txt">they're excluded from the Google search index</a>. The Facebook developer experience is a fractal of <a href="http://b.z19r.com/post/did-you-just-tell-me-to-go-fuck-myself">being told to go fuck yourself</a>.</p>

<p>The story might end there. We have to create an app first, but the URL redirection method <em>is</em> just a link. So it should be equally simple, right? No. It doesn't work. I got an error 100: &quot;Invalid parameter (requires valid <code>redirect_uri</code>).&quot; What <em>is</em> a valid <code>redirect_uri</code>? What's an invalid <code>redirect_uri</code>? There is nothing in the documentation. Why was mine invalid? The error doesn't say. I'd fat-fingered it and missed off an ampersand so I wasn't supplying a <code>redirect_uri</code> at all, but there's a lot of voodoo out there about <a href="http://stackoverflow.com/a/7566147">not escaping the URL</a> or <a href="http://stackoverflow.com/a/3619749">setting your app domain</a>. Obviously I wasted an hour on that before realising my mistake. Couldn't we have had a &quot;missing required parameter&quot; error instead of &quot;invalid parameter&quot;? No, because then you wouldn't feel the full force of Facebook's contempt. And even then, when you've finally got it working, <a href="https://developers.facebook.com/bugs/1527170174175092/">mobile users won't be able to share it</a>. </p>

<p><a href="http://spectrum.ieee.org/at-work/innovation/facebook-philosophy-move-fast-and-break-things">Move fast and break things</a> is a valid philosophy for a startup, but it doesn't work if you're a platform. <a href="http://www.w3.org/Provider/Style/URI.html">Cool URLs don't change</a>; cool APIs don't flipflop around based on whimsy. </p>

<p><em>Further reading: <a href="http://www.bogost.com/blog/oauth_of_fealty.shtml">oAuth of Fealty</a> by Ian Bogost.</em></p>

<div class="footnotes">
<hr />
<ol>

<li id="fbfn:1">
<p>Laughably describing the Share Button as a 'simpler' alternative.  <a href="#fbfnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fbfn:2">
<p>This step includes an implicit &quot;... and trust Facebook to do something harmful to your page, either accidentally or intentionally.&quot; <a href="#fbfnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2014/04/08/burn-facebook-to-the-ground</guid><pubDate>Tue, 08 Apr 2014 14:15:06 +0100</pubDate></item><item><title>FAWM 2014</title><link>https://alexpounds.com/blog/2014/03/31/fawm-2014</link><description><![CDATA[<p>Last year <a href="/blog/2013/03/31/my-fawm-2013">I took part in FAWM</a> &ndash; <a href="http://fawm.org/">February Album Writing Month</a>. I did it again last year, and actually made an album this time: 15 songs in 28 days. It was super-stressful, and for the sake of my sanity I should not be allowed to aim for 14 songs in 2015. </p>

<p>Most of it was made on my iPad, although I finished a couple of tracks in <a href="http://ardour.org/">Ardour</a>. I used a lot of GarageBand, along with <a href="http://www.propellerheads.se/products/figure/">Figure</a>, <a href="http://www.propellerheads.se/products/thor/">Thor</a>, <a href="http://www.korg.com/us/products/software/korg_gadget_for_ipad/">Korg Gadget</a>, and <a href="http://syntheticbits.com/funkbox.html">Funkbox</a>. I bought <a href="http://www.amazon.co.uk/gp/product/B0068VPC6W/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=B0068VPC6W&amp;linkCode=as2&amp;tag=alexpoundscom-21">a cable that let me record my guitar from my iPad</a>, and friends lent me a banjo &amp; <a href="http://www.amazon.co.uk/gp/product/B001RBY2CI/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=B001RBY2CI&amp;linkCode=as2&amp;tag=alexpoundscom-21">a decent audio recorder</a>. </p>

<p>It's a mix of acoustic recordings, synthy dance electronica, and atmospheric darker electronic music. You can <a href="http://fawm.org/fawmers/creature/">explore it track-by-track on my FAWM page</a> (until 2015, as the site retires older stuff each year), or <a href="/static/blog/2014/album.zip">download the whole album as a zip</a>. I've also included the MP3s below. </p>

<ol>
<li><a href="/static/blog/2014/01%20-%20A%20Departure.mp3">A Departure</a> (acoustic folk-rock)</li>
<li><a href="/static/blog/2014/02%20-%20Let%27s%20Get%20Started.mp3">Let's Get Started</a> (dance/electronica)</li>
<li><a href="/static/blog/2014/03%20-%20Are%20You%20Receiving.mp3">Are You Receiving?</a> (synthpop/electronica)</li>
<li><a href="/static/blog/2014/04%20-%20Synthetic%20Floor%20Filler.mp3">Synthetic Floor Filler</a> (dance/electronica)</li>
<li><a href="/static/blog/2014/05%20-%20It%27s%20Going%20To%20Happen.mp3">It's Going To Happen</a> (spoken word/folk-rock)</li>
<li><a href="/static/blog/2014/06%20-%20String%20Theory.mp3">String Theory</a> (instrumental/folk)</li>
<li><a href="/static/blog/2014/07%20-%20Time%20Slips%20Past.mp3">Time Slips Past</a> (chiptune/electronica)</li>
<li><a href="/static/blog/2014/08%20-%20Boopwub.mp3">Boopwub</a> (electronica/dubstep)</li>
<li><a href="/static/blog/2014/09%20-%20Ice%20Giants.mp3">Ice Giants</a> (dance/electronica)</li>
<li><a href="/static/blog/2014/10%20-%20Numericalities.mp3">Numericalities</a> (dance/electronica)</li>
<li><a href="/static/blog/2014/11%20-%20Forever%20Safe.mp3">Forever Safe</a> (ambient/electronica)</li>
<li><a href="/static/blog/2014/12%20-%20Elongate%20Thistledown.mp3">Elongate Thistledown</a> (dance/synthpop)</li>
<li><a href="/static/blog/2014/13%20-%20Thanks%2C%20Steve.mp3">Thanks, Steve</a> (instrumental/soft rock)</li>
<li><a href="/static/blog/2014/14%20-%20Potbound%20Mint.mp3">Potbound Mint</a> (synthpop/waltz)</li>
<li><a href="/static/blog/2014/15%20-%20Sometimes%20Things%20Just%20Go%20Your%20Way.mp3">Sometimes Things Just Go Your Way</a> (instrumental/chamber pop)</li>
</ol>

<p>As an extra bonus track, <a href="/static/blog/2014/Rare%20Synths.mp3">here's a dance track I made post-FAWM</a>. Unlike last year, I'd like to keep making music in the rest of 2014. I must have at least another EP in me.</p>
]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2014/03/31/fawm-2014</guid><pubDate>Mon, 31 Mar 2014 23:47:54 +0100</pubDate></item><item><title>Products with benefits</title><link>https://alexpounds.com/blog/2014/01/30/products-with-benefits</link><description><![CDATA[<p><em>The first in an occasional series about product design heuristics. The second part <a href="/blog/2015/10/06/the-friend-multiplier">is about what &quot;social&quot; should really mean</a>.</em> </p>

<p>I generally <a href="/cv">work</a> with startups, which means I'm working with companies that are still trying to figure out what they're building. I'm not a product manager, but over time I've assembled some heuristics that help figure out if a product is on track. </p>

<p><strong>When you're building a user-driven product or adding a feature, the user must benefit and the company must benefit.</strong></p>

<p>This sounds obvious but it's surprising how many companies put their own wishes above their customers'. It's an approach that can pay off in the short term, but at best you're growing an indifferent, surly customer base. At worst, you're driving people away. Human beings have very little patience. If you're not putting them first, they'll go somewhere else. </p>

<p>It's a heuristic &ndash; not a cast-iron rule &ndash; so it's not a disaster if you take a different path. But you <em>are</em> swimming against the tide, and you're going to have an uphill battle<sup><a href="#pbfn:1" id="pbfnref:1">1</a></sup>. You're going to have to explain to your users why they should do what you want, or create something so compelling they'll jump through your hoops. Equally, if users benefit but the business doesn't, make sure you have a plausible plan for the long run. Your business isn't going to implode, but it might limp along, struggle to attract users, or fail to evoke the passionate response you want. </p>

<h2 id="anexample">An example</h2>

<p>A startup is building a <a href="https://foursquare.com/">Foursquare</a>-like service, but instead of checking in to places users will write a short review. The startup thinks they'll gather deeper knowledge about the places you visit, and that they can monetise that database. But they're missing a key step: why will a user write a review? What does the user get out of it? </p>

<p>Writing a review is a lot of effort. Even if it's just a sentence or two, the user still has to figure out: </p>

<ul>
<li>What's good about this place?</li>
<li>What's bad about it?</li>
<li>Am I broadly for or against?</li>
<li>How am I going to express that in words?</li>
</ul>

<p>And don't forget the user's out in the world, probably with friends. Will they really ignore the people with them and tap out a review on their phone? This is starting to sound like a rather anti-social product. Users won't complain about it; they just won't use it. Check-ins are already an unnatural behaviour &ndash; something a user's persuaded into trying, rather than demanding &ndash; and the mandatory review step makes that even harder. </p>

<h2 id="carrotandstick">Carrot and stick</h2>

<p>People use your features for two broad reasons: </p>

<ol>
<li>Good things happen if they do.</li>
<li>Bad things happen if they don't.</li>
</ol>

<p>The first motivation is infinitely more preferable: the carrot is better than the stick. If you're lucky you can sometimes force things on your user, but everything flows more smoothly if the users want it themselves. </p>

<p>People shop on Amazon because they want cheap products conveniently delivered to them. They post statuses on Facebook so their friends click 'Like'. They sign up to Groupon to get big discounts in their inbox. Users actively want these things: they would complain if you took them away. But there's a benefit to the companies too: profit for Amazon, and engaged users for Facebook &amp; Groupon<sup><a href="#pbfn:2" id="pbfnref:2">2</a></sup>.</p>

<p>The second option puts your company's needs first. It's a mild form of blackmail. You're putting an obstacle in front of your user, and hoping that they want your offering enough to put up with your bullshit<sup><a href="#pbfn:3" id="pbfnref:3">3</a></sup>. You can spot these by looking for <em>double</em> obstacles: something you've added to make the first obstacle work<sup><a href="#pbfn:4" id="pbfnref:4">4</a></sup>. YouTube's first obstacle was &quot;Watch this advert before you see a video&quot;, but nobody wants to watch an ad. So they added a second obstacle that makes you wait 5 seconds before you can skip it. Groupon <em>really</em> wants to email you every day<sup><a href="#pbfn:5" id="pbfnref:5">5</a></sup>, so as soon as you land on a Groupon page they show you an undismissable box demanding you sign up. </p>

<a href="/static/blog/2014/screenshot-groupon.png"><img src="/static/blog/2014/screenshot-groupon.tmb.png" alt="A screenshot of the undismissable Groupon popup." /></a>

<p>Nobody on the internet thinks to themselves &quot;I really wish this web page would demand my email address the instant I visit it.&quot; Groupon's betting that the people it turns off &ndash; the people who say &quot;Stuff this&quot; and close the tab &ndash; are worth less to them than the email addresses from casual visitors who want to see the offer. You could argue that users benefit from this too, as they get offers in their inbox every day, but it's an arm-twisty way of getting users. The user didn't get the chance to see some Groupon deals and decide to sign up because they liked the look of them: they signed up because that's the only way to see the offer in the first place. </p>

<p>Streaming music is another example. Companies like <a href="http://rdio.com/">Rdio</a>, <a href="http://pandora.com/">Pandora</a>, and <a href="http://last.fm/">Last.fm</a>. Their streaming radio products generally limit how many times per hour you can skip a track. It's because of licensing laws, and the costs of licensing music: labels charge less for &quot;radio&quot; plays than &quot;on-demand&quot; plays, and it's easier to convince the labels that you're in the former category if you have limitations. Users hate it, but the businesses think it's the only way they can survive<sup><a href="#pbfn:6" id="pbfnref:6">6</a></sup>.</p>

<h2 id="magicalsticksthatturnintocarrots">Magical sticks that turn into carrots</h2>

<p>There are occasional circumstances where you obstruct your user for a good reason: for the good of the community. A real life example is airport security: nobody wants to have to queue for ages and get searched, but most people don't want bombs on planes. So we mildly inconvenience everybody so society avoids hostage situations. A tech example is <a href="http://dattch.com/">Dattch</a>, a lesbian dating app. There's a bunch of people on the internet who love to spam &amp; harass lesbians. So Dattch insists you sign in with Facebook, and every profile is screened by a human to ensure it's real. It's not that they think their users want to wait for several hours as soon as they sign up &ndash; it's that it's better for the rest of the community if the company has a chance to screen out the weirdos. </p>

<h2 id="whosgettingitright">Who's getting it right?</h2>

<p>It's hard to give examples of companies that get it right, because it looks <em>so damn obvious</em>. Consider any online shop, pretty much: people want to buy things, and the company wants to sell things. As long as the customers are happy with the product and the business is making a profit, everybody's happy. Or consider Dropbox: users benefit from having their files available everywhere, and Dropbox benefits from power users who buy premium accounts (and from being the <em>de facto</em> way of syncing files across devices). </p>

<p>Marketplace leaders are good examples, too &ndash; the eBays &amp; AirBNBs of the world. Their users are both buyers &amp; sellers: buyers win by having easier access to more products/accommodation, and the sellers can reach a bigger audience or even sell something they couldn't before. The business wins by taking a commission.</p>

<p>And despite the way they haemorrhage money, music streaming services would argue that they benefit from data when users listen. It can use that data to improve its personalisation services, and also sell aggregate information back to the music labels. It's still a <a href="http://mashable.com/2009/12/08/myspace-shuts-down-imeem/">cut</a>-<a href="http://www.theverge.com/2013/11/22/5134694/turntable-fm-shutting-down-focus-on-live-concert-service">throat</a> <a href="http://www.wired.com/listening_post/2008/08/life-after-muxt/">business</a>, which demonstrates that even if you <em>think</em> you've ticked both boxes you're not guaranteed success.</p>

<h2 id="thetakeaway">The takeaway</h2>

<p>When creating a product or adding a new feature, make sure that both the user and your company will benefit. Users are fickle; they won't do things solely because you want them to. There's got to be something in it for them. And likewise, you won't last long as a business if you give the users everything: there's got to be something in it for the company too. It might be a long-term payoff. It might not be direct. It's OK if it's not <em>always</em> there, but have a clear reason in your mind to forego it.</p>

<div class="footnotes">
<hr />
<ol>

<li id="pbfn:1">
<p>I enjoyed this mixed metaphor so I left it in. <a href="#pbfnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="pbfn:2">
<p>&quot;Engaged users&quot; means &quot;People use your product&quot;, which means &quot;We can sell things to them.&quot; Groupon sells to people directly. Facebook sells advertising space, which is an opportunity for someone else to sell to their users.  <a href="#pbfnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="pbfn:3">
<p>This isn't the same as a <a href="http://darkpatterns.org/">dark pattern</a> &ndash; dark patterns are actively trying to trick people. These examples are trying to work around human nature.  <a href="#pbfnref:3" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="pbfn:4">
<p>Another way of spotting this is asking, &quot;Did this request come from the advertising department?&quot; <a href="#pbfnref:4" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="pbfn:5">
<p>If they email you every day, they can sell to you every day. If they sell to you every day, you're more likely to buy something. <a href="#pbfnref:5" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="pbfn:6">
<p>Spotify is taking a different approach: they're trying to get a huge audience before they run out of money. They have higher licensing costs, but if they can get enough users then economies of scale kick in and they'll be profitable.  <a href="#pbfnref:6" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2014/01/30/products-with-benefits</guid><pubDate>Thu, 30 Jan 2014 23:48:13 +0000</pubDate></item><item><title>What makes Bit Pilot fun</title><link>https://alexpounds.com/blog/2013/12/02/what-makes-bit-pilot-fun</link><description><![CDATA[<img src="/static/blog/2013/bitpilot.png" alt="A screenshot from the game Bit Pilot" title="I hope you noticed I achieved a respectable score before taking this screenshot." />

<p>Yesterday, for the first time in about a year, I played <em><a href="http://www.bitpilotgame.com/">Bit Pilot</a></em>. It's an astonishingly good game, and I found myself pondering what qualities made it fun. Games aren't made via checklists, of course. You can't take these elements, tick them off, and expect to have a fun game. There's also a <a href="https://twitter.com/acreature/status/84317218313220097">standard disclaimer</a>. But that doesn't mean we shouldn't try to learn from the work of others. So, why is <em>Bit Pilot</em> fun?</p>

<p><em>Bit Pilot</em> has a simple concept, well-executed. You control a spaceship in a restricted playing area. Dodge the asteroids and laser beams. Collect power-ups if you can. That's it: there's no sprawling back-story, no giant sandbox, no growling beefy protagonist. Just you versus the game &ndash; and you will always lose. There's also no victory screen: you're pitted against your own prior performance (your high score) and any friends you can persuade to play too. This simplicity is an attraction. But a simple idea, no matter how elegant, isn't going to make people play for hours unless there's something more at work.</p>

<h2>Balancing a chair on two legs</h2>

<p>You're sitting at a desk and you push yourself away from it and now this four-legged chair is balanced on its two hind legs and you. are. <em>awesome</em>. We've all delighted in that, right? There's two unconscious thoughts that ping-pong back and forth while you're doing this: </p>

<ol>
<li>I'm so skilled. Check out my goat-like balance. This is ace. <em>I'm</em> ace.</li>
<li>WHOA FUCK I ALMOST LOST IT phew I'm fine</li>
</ol>

<p>It's this interplay that <em>Bit Pilot</em> replicates. Most of the time you feel in control and impressed with your abilities, but there's these little nudging pokes that knock you off balance. It's not a stable system; sometimes you'll get away with it, but in the end you'll lose. You come back for more because of the times you get away with it, and because the feeling of control is so addictive. </p>

<h2>Pushing your boundaries</h2>

<p>The reason you always lose is because <em>Bit Pilot</em> gently but constantly pushes on your boundaries. The special asteroids and laser beams are part of this, but the main pressure is the asteroids becoming bigger. Over time there's less space and more asteroid. You can't win; eventually there'll be no space left.</p>

<p><em><a href="http://superhexagon.com/">Super Hexagon</a></em> is another game that got its hooks into me. It's difficult in a different way; it's far more overwhelming at first<sup><a href="#fn:1" id="fnref:1">1</a></sup>. There's so much happening on-screen it's hard to grasp what's happening. And just when you start to get a grip, the game speeds up, or reverses direction, or introduces a new obstacle. <em>Super Hexagon</em> doesn't give me the same balanced-on-a-knife-edge feeling, though maybe I've played it too much. When I die in <em>Bit Pilot</em>, I think &quot;I should have avoided that.&quot; When I die in <em>Super Hexagon</em>, I think &quot;Yeah, you got me.&quot; Infinite runners like <em><a href="http://adamatomic.com/canabalt/">Canabalt</a></em> have the purest implementation of this: they speed up the longer you play, giving you less time to react.</p>

<h2>A balanced difficulty curve</h2>

<p>Some games don't forgive mistakes. <em>Super Hexagon</em> and <em>Canabalt</em> both have instadeath: one mistake and you die. Other games give you lives. <em>Bit Pilot</em> has a lives system &ndash; your ship starts with two shields, and you can accumulate more &ndash; but it's more effective than your standard 3-lives-then-game-over mechanism. </p>

<p>There's no penalty for losing a life &ndash; no going back to the start of a level or losing your power-ups. The graphics and sound tell you you messed up, but there's no immediate consequence beyond feeling more <em>exposed</em> than before. You can also pick up extra shields, until your ship is nestled in the centre of a giant hexagonal onion. But it gets harder and harder to keep them: the more shields you have, the bigger you are. You can't slip through tiny gaps any more. Conversely, you become a smaller target as you get closer to death. The stakes are higher, but the odds are more in your favour. </p>

<h2>No time to reflect</h2>

<p>A key hook in both <em>Super Hexagon</em> and <em><a href="http://www.supercratebox.com/">Super Crate Box</a></em> is keeping the time between &quot;game over&quot; and &quot;new game&quot; as short as possible. One quick reflexive tap and you're back in the action. No time to think about the previous game; stay in the zone, and keep playing. It's not a case of thinking &quot;Just one more go.&quot; It's a case of not thinking at all. </p>

<h2>Perfect controls</h2>

<p>A game has <em>perfect</em> controls if you never think about them. <em>Bit Pilot</em> has a neat two-thumbs method that is a devil to explain, but it feels fantastic. Essentially, your two thumbs sum together. You can't understand it without playing the game, but it enables tiny intricate moves as well as big sweeping manoeuvres. You won't make many of those, though; part of its appeal is that (despite the fast pace) it's a game of subtlety. You'll die quickly if you pinball around the screen. Patiently wait in the middle, though, and make small adjustments... you'll live a little longer. </p>

<p><em>Super Crate Box</em>, by contrast, has infuriating controls<sup><a href="#fn:2" id="fnref:2">2</a></sup>. PC to touchscreen ports are always hard because on-screen buttons suck. Around 50% of my <em>Super Crate Box</em> deaths are down to a lack of control; things going awry between my fingers and the device. I end up jumping when I meant to shoot, shooting when I tried to jump, my jump going awry. It's frustrating, and it never happens in <em>Bit Pilot</em> or <em>Super Hexagon</em>. The chair-balance feeling depends on creating a feeling of mastery; you can't get that if it doesn't feel like your avatar<sup><a href="#fn:3" id="fnref:3">3</a></sup> obeys your commands. </p>

<h2>Making it happen in your own work</h2>

<p>I'm not a game developer, so I can't tell you how to build the perfect controls or chair-balancing feeling into your own games. I suspect it's art, not science; tweaking and playtesting until it feels right. I never got obsessed by <em>Canabalt</em>, but the developer <a href="http://www.gamasutra.com/blogs/AdamSaltsman/20100930/6096/">spent a lot of time tweaking it</a> until it played well. </p>

<p>And if your game lacks these qualities, don't worry. These principles aren't universal. Plenty of great games are made of different elements. There are games I love that are story-driven, or subverting the form, or wonderful art, or are simply absurd. But if your game lacks tension, excitement, and stickiness, think about whether you're lacking that chair-balanced-on-two-legs feeling.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p>I think Super Hexagon is what my mother fears all computer games are: requiring twitchy, lightning-quick reflexes, along with hypnotic graphics and bleepy music. <a href="#fnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:2">
<p>Though I have only played it on iOS.<a href="#fnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="fn:3">
<p>By which I mean &quot;the in-game dingus that represents you, the player&quot;.<a href="#fnref:3" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>
</ol>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2013/12/02/what-makes-bit-pilot-fun</guid><pubDate>Mon, 02 Dec 2013 19:17:37 +0000</pubDate></item><item><title>My laser-cut iPhone stand</title><link>https://alexpounds.com/blog/2013/11/10/my-laser-cut-iphone-stand</link><description><![CDATA[<ul class="blog gallery">
<li><a href="/static/images/blog/2013/iphonestandinuse.jpg"><img src="/static/images/blog/2013/iphonestandinusetmb.jpg" alt="The iPhone stand in use." /></a></li>
<li><a href="/static/images/blog/2013/iphonestandrear.jpg"><img src="/static/images/blog/2013/iphonestandreartmb.jpg" alt="The iPhone stand, from the rear." /></a></li>
</ul>

<p>When I got my iPhone I wanted a desk stand to accompany it. A friend had a stand that was simply a rubber strap with notches at each end. It seemed ideal &ndash; simple, portable, hard to break. But I couldn't find it online &amp; my friend disavowed all knowledge, so I made one instead. </p>

<p>Unlike my <a href="/blog/2012/08/26/my-laser-cut-ipad-stand">laser-cut iPad stand</a>, this one didn't go so well. Choosing silicone was my first mistake. It seemed the ideal material: safe to laser cut, reasonably priced, a good balance of stiffness and floppiness. But silicone's also heat-resistant &ndash; that's why it's used for cookware &ndash; and laser cutters use heat to cut. It didn't cut cleanly; no matter what I tried I had to finish each stand with a craft knife. I used 4mm silicone; thinner might have worked better, but it would be less rigid &amp; durable.</p>

<p>My second mistake was also born of ignorance: few iPhone apps have landscape mode. iOS itself won't switch to landscape, so if you use the stand you'll be tilting your head a lot. The stand works in a portrait orientation, just about, but I don't trust it.</p>

<p>I can't recommend using this stand. But if you've been looking for a rubber strap stand, can't find one to buy, and want to make one of your own: this might be a good starting point. There's nothing wrong with the design, it's just not that useful. (And pick a different rubber). </p>

<ul>
<li><a href="/static/iphonestand-v02.dxf">Download the DXF file</a></li>
<li><a href="http://www.thingiverse.com/thing:176193">Check it out on Thingiverse</a></li>
</ul>

<ul class="blog gallery">
<li><a href="/static/images/blog/2013/iphonestandcadfile.jpg"><img src="/static/images/blog/2013/iphonestandcadfiletmb.jpg" alt="A screenshot of the design." /></a></li>
<li><a href="/static/images/blog/2013/iphonestandonwhite.jpg"><img src="/static/images/blog/2013/iphonestandonwhitetmb.jpg" alt="The final result." /></a></li>
<li><a href="/static/images/blog/2013/iphonestandangle.jpg"><img src="/static/images/blog/2013/iphonestandangletmb.jpg" alt="The iPhone stand with the phone, shown at an angle." /></a></li>
</ul>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2013/11/10/my-laser-cut-iphone-stand</guid><pubDate>Sun, 10 Nov 2013 22:24:34 +0000</pubDate></item><item><title>Don't start with the foundations</title><link>https://alexpounds.com/blog/2013/10/20/dont-start-with-the-foundations</link><description><![CDATA[<p>I had an interesting conversation recently. It was something of a role reversal; the product person came at it from a data perspective, and I came at it from a product perspective. We were trying to figure out the roadmap &ndash; what features we could build, what features we <em>should</em> build, and their priority.</p>

<p>I produced a useful metaphor as part of this, but let's talk about the issue first. When you're developing a product or service, you should start at the front. What <em>is</em> the service? How will people interact with it? Why are people paying you for it<sup><a href="#foundfn:1" id="foundfnref:1">1</a></sup>? How does it fit in with your existing/future services? You need this in a little more detail than an elevator pitch, but not to the level of a specification for external developers.</p>

<p>Once you've got this planning done you can figure out how to build it. That's the point to start thinking about the data you'll need to execute your plans &ndash; not before.</p>

<p>My conversation partner approached this from the other direction. &quot;We're going to need data from our users for whatever we build,&quot; he thought, &quot;And data is going to drive the business. Let's start there. What data is easy to collect? What can we do with that?&quot;</p>

<p>That's a valid starting point for brainstorming. It can help you think up enhancements and quick wins. But it's not a good way to design your core product<sup><a href="#foundfn:2" id="foundfnref:2">2</a></sup>. Chances are if it's easy, other people are already doing it. And even if it was <em>really hard</em> to collect or quantify certain data, if it's core to your business you'll have to figure out a way to capture it. </p>

<p>The data you collect &amp; process is the crucial base for your product, but you don't start there. The metaphor: </p>

<p><strong>If you're building a house, you'll need solid foundations. But you don't design the foundations first and then ask, &quot;What can I build on top of this?&quot;</strong></p>

<div class="footnotes">
<hr />
<ol>

<li id="foundfn:1">
<p>The $10 equivalent of this sentence: what's the value proposition? <a href="#foundfnref:1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

<li id="foundfn:2">
<p>I'm using &quot;product&quot; and &quot;service&quot; interchangeably in this article. I don't think any of this thinking is specific to one or the other.  <a href="#foundfnref:2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>

</ol>
</div>]]></description><guid isPermaLink="true">https://alexpounds.com/blog/2013/10/20/dont-start-with-the-foundations</guid><pubDate>Sun, 20 Oct 2013 18:47:27 +0100</pubDate></item></channel></rss>
