<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Caius Theory</title><link>https://caiustheory.com/</link><description>Recent content on Caius Theory</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><copyright>This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License</copyright><lastBuildDate>Tue, 23 Dec 2025 10:00:00 +0000</lastBuildDate><item><title>jj jj jj jj jj</title><link>https://caiustheory.com/jj-jj-jj-jj-jj/</link><pubDate>Tue, 23 Dec 2025 10:00:00 +0000</pubDate><guid>https://caiustheory.com/jj-jj-jj-jj-jj/</guid><description>&lt;p>In a similar vein to &lt;a href="/git-git-git-git-git/">git git git git git&lt;/a>, if you&amp;rsquo;re using &lt;a href="https://www.jj-vcs.dev/">jj&lt;/a> and find you&amp;rsquo;ve accidentally typed one &lt;code>jj&lt;/code> too many in the command line, it errors at you. In this case we&amp;rsquo;re trying to pull the id of the current changeset we&amp;rsquo;re editing:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ jj jj show -T &lt;span class="s1">&amp;#39;change_id.short()&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">error: unrecognized subcommand &lt;span class="s1">&amp;#39;jj&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Usage: jj &lt;span class="o">[&lt;/span>OPTIONS&lt;span class="o">]&lt;/span> &amp;lt;COMMAND&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">For more information, try &lt;span class="s1">&amp;#39;--help&amp;#39;&lt;/span>.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>How annoying. Now we could solve this with a shell alias, but &lt;code>jj&lt;/code> also allows us to define alias&amp;rsquo; in the configuration (much like git!), and combined with &lt;a href="https://docs.jj-vcs.dev/latest/cli-reference/#jj-util-exec">&lt;code>jj util exec&lt;/code>&lt;/a> we should be able to have it run the rest of the line nay bother.&lt;/p>
&lt;p>Thinking it through, the initial &lt;code>jj&lt;/code> will be exec&amp;rsquo;d by the shell, so that&amp;rsquo;s gone already. The second &lt;code>jj&lt;/code> is then evaluated as the alias, so that&amp;rsquo;s gone too. The remaining arguments passed to the alias are &lt;code>[&amp;quot;show&amp;quot;, &amp;quot;-T&amp;quot;, &amp;quot;change_id.short()&amp;quot;]&lt;/code> so if we just exec those it&amp;rsquo;ll error trying to run &lt;code>show&lt;/code> as a binary. We can avoid that by having it exec jj then the arguments from the alias.&lt;/p>
&lt;p>Drop the alias in a jj config file (&lt;code>jj config edit&lt;/code> is super useful for editing these, or there&amp;rsquo;s &lt;code>jj config set&lt;/code> to update it from the shell) and then we can test it works.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">aliases&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># jj all the way down&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">jj&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;util&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;exec&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;jj&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Lets try our original nested command again and see if we get to see our sweet sweet change id:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ jj jj show -T &lt;span class="s1">&amp;#39;change_id.short()&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">error: unexpected argument &lt;span class="s1">&amp;#39;-T&amp;#39;&lt;/span> found
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> tip: to pass &lt;span class="s1">&amp;#39;-T&amp;#39;&lt;/span> as a value, use &lt;span class="s1">&amp;#39;-- -T&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Usage: jj util &lt;span class="nb">exec&lt;/span> &lt;span class="o">[&lt;/span>OPTIONS&lt;span class="o">]&lt;/span> &amp;lt;COMMAND&amp;gt; &lt;span class="o">[&lt;/span>ARGS&lt;span class="o">]&lt;/span>...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">For more information, try &lt;span class="s1">&amp;#39;--help&amp;#39;&lt;/span>.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Oh. Our &lt;code>-T&lt;/code> argument is being interpreted by &lt;code>jj util exec&lt;/code>, not by the &lt;code>jj&lt;/code> command we&amp;rsquo;re running. Classic nested argument parsing when you&amp;rsquo;re trying to invoke another command. Luckily shell/exec has a solution to this, passing &lt;code>--&lt;/code> as an argument stops parsing all remaining arguments so they are passed along verbatim.&lt;/p>
&lt;p>With that in mind we can amend our alias to run &lt;code>jj util exec&lt;/code> and then stop interpreting any further arguments.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">aliases&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># jj all the way down&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">jj&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;util&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;exec&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;--&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;jj&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now we should be able to see our change id without any issues, no matter how many nested &lt;code>jj&lt;/code>s there are in the command!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ jj show -T &lt;span class="s1">&amp;#39;change_id.short()&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">upvqxuzzvxtx
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ jj jj show -T &lt;span class="s1">&amp;#39;change_id.short()&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">upvqxuzzvxtx
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ jj jj jj jj jj show -T &lt;span class="s1">&amp;#39;change_id.short()&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">upvqxuzzvxtx
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ jj jj jj jj jj jj jj jj jj jj jj jj jj jj jj jj jj show -T &lt;span class="s1">&amp;#39;change_id.short()&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">upvqxuzzvxtx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Happy committing.&lt;/p></description></item><item><title>Apple Watch Band Mnemonic</title><link>https://caiustheory.com/apple-watch-band-mnemonic/</link><pubDate>Sun, 27 Jul 2025 18:57:48 +0100</pubDate><guid>https://caiustheory.com/apple-watch-band-mnemonic/</guid><description>&lt;p>I&amp;rsquo;ve been wearing an &lt;a href="https://www.apple.com/watch/">Apple Watch&lt;/a> pretty regularly for nearly a decade at this point (October 2015), and have picked up a few bands over time that I swap between. Commonly I&amp;rsquo;ll swap from a fabric based band to a rubber/silicone based band when doing DIY or sports as they seem to stand up better over time to those activities.&lt;/p>
&lt;p>Without fail every single time I swap the band I have to think &lt;strong>really&lt;/strong> hard which way round the new band is going onto the watch body. For the fabric loops is it the single end or the hooped end going on the top of the body? For the two piece bands is it the short or the long band that goes on the top of the body?&lt;/p>
&lt;p>I finally figured out a mnemonic to help me remember, and having used it for a few weeks it appears to have lodged in my brain. Pretty simple, it&amp;rsquo;s a single word:&lt;/p>
&lt;blockquote>
&lt;p>Longbottom.&lt;/p>
&lt;/blockquote>
&lt;p>For the two piece straps the longer one goes on the bottom (and shorter on the top), and for the fabric loops the hoop goes on the bottom because it has the longer piece of the strap running through it. &lt;em>(The latter is more tenuous.)&lt;/em>&lt;/p>
&lt;p>To remember longbottom specifically, the first reference that comes to my mind is Neville Longbottom, who went from being a weed to being pretty awesome in a well known series of books&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> and films. Secondly it&amp;rsquo;s a place in Middle-Earth, where &lt;a href="https://lotr.fandom.com/wiki/Pipe-weed">Pipe-weed&lt;/a> was first grown.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>With an author who appears to be doing their best to totally alienate any fanbase. Sigh.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Set Up Rails Activestorage With Azure Securely</title><link>https://caiustheory.com/set-up-rails-activestorage-with-azure-securely/</link><pubDate>Wed, 02 Oct 2024 22:28:49 +0100</pubDate><guid>https://caiustheory.com/set-up-rails-activestorage-with-azure-securely/</guid><description>&lt;p>&lt;a href="https://rubyonrails.org">Ruby on Rails&lt;/a> has built-in support for managing uploaded files with &lt;a href="https://github.com/rails/rails/tree/main/activestorage#readme">ActiveStorage&lt;/a>, which both cleans up your application code and acts as an abstraction over different storage backends. Azure Storage is one of the supported backends, but configuring it securely can take a little figuring out.&lt;/p>
&lt;p>The most sensible way I&amp;rsquo;ve found to have it configured is with files stored having no public access, but allowing temporary access via signed URLs for both uploads &amp;amp; downloads. ActiveStorage happily generates these URLs for us which makes it easy for developers to use and transparent to users, whilst keeping their data as secure and protected as possible. From a technical point of view, this also allows upload and download between Azure Storage and the user&amp;rsquo;s browser, without proxying all the data through your Rails app.&lt;/p>
&lt;h3 id="azure-setup">Azure setup&lt;/h3>
&lt;p>We&amp;rsquo;ll be storing the files in Azure as blobs within &lt;a href="https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction">Azure Blob Storage&lt;/a>. Blobs live within a Storage Container which lives within a Storage Account, which is created in a specific geographical region and Resource Group.&lt;/p>
&lt;p>To create the above, we&amp;rsquo;ll need access to an Azure Subscription with permissions to create the resources. (Most of the time you will already be an admin on the subscription, so can ignore checking this. If you get permission errors creating the below, you&amp;rsquo;ll need to go talk to your admin.)&lt;/p>
&lt;p>Most resources in Azure need to live within a Resource Group, which it&amp;rsquo;s suggested you use to group related resources together. If there isn&amp;rsquo;t already a resource group for your application resources, create one.&lt;/p>
&lt;p>Next we need to create a Storage Account in the main location for the app and nested in the Resource Group from above. The following settings are split across multiple pages, click &amp;ldquo;Next&amp;rdquo; to advance to next bit of the form:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Storage account name&lt;/strong>: 3-24 numbers/lowercase letters only, unique across all storage accounts globally in Azure. Good luck. (eg, &lt;code>st123someappproduksth&lt;/code>)&lt;/li>
&lt;li>&lt;strong>Region&lt;/strong>: choose for your app location (eg, UK South)&lt;/li>
&lt;li>&lt;strong>Performance&lt;/strong>: Standard (general purpose v2 account)&lt;/li>
&lt;li>&lt;strong>Redundancy&lt;/strong>: Zone-redundant storage (ZRS) if possible. (Some regions don&amp;rsquo;t support it, choose Locally-redundant storage (LRS) in those.)&lt;/li>
&lt;li>&lt;strong>Enable infrastructure encryption&lt;/strong>: Check the box, it&amp;rsquo;s free.&lt;/li>
&lt;li>&lt;strong>Tags&lt;/strong>: tag the resource according to your internal conventions/policies (eg, &lt;code>terraform:false&lt;/code>)&lt;/li>
&lt;/ul>
&lt;p>Create the Storage Account and wait for it to complete. Next we&amp;rsquo;ll create the Storage Container nested under the Storage Account which is where our actual files will be uploaded to. Find the Storage Account we created in the portal and click &amp;ldquo;Containers&amp;rdquo; in the sidebar, then &amp;ldquo;+ Container&amp;rdquo; above the table listing the containers.&lt;/p>
&lt;p>Add a sensible name for the Container, which is easier because there are &lt;a href="https://learn.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names">fewer restrictions on this name&lt;/a>. (eg, &lt;code>dragon-myapp-production-uksouth-activestorage&lt;/code>.) Create the container and wait for that to complete.&lt;/p>
&lt;p>Navigate back to viewing the Storage Account and select &amp;ldquo;Access Keys&amp;rdquo; in the sidebar. Make a note of the Key value (for key1) for use later configuring Rails. If you need to rotate the access keys later without causing an outage, you can update the app to use the Key from key2 and then rotate the key for key1 from the UI.&lt;/p>
&lt;p>The final configuration we might need to set in Azure is allowing direct uploads from our app to the container. Due to this being client-side requests we need the Cross-Origin Resource Sharing (CORS) headers to allow this from Azure&amp;rsquo;s side. Without these in place you will get permissions errors from browsers trying to make requests directly to Azure. If you&amp;rsquo;re not using ActiveStorage&amp;rsquo;s Direct Upload feature, you can skip this.&lt;/p>
&lt;p>Find &amp;ldquo;Resource Sharing (CORS)&amp;rdquo; in the sidebar for the Storage Account. Add a new entry to the &amp;ldquo;Blob service&amp;rdquo; table:&lt;/p>
&lt;ul>
&lt;li>Allowed origins: comma-separated list of all your app domains using this storage.&lt;/li>
&lt;li>Allowed methods: &lt;code>GET&lt;/code>, &lt;code>POST&lt;/code>, &lt;code>OPTIONS&lt;/code>, &lt;code>PUT&lt;/code>&lt;/li>
&lt;li>Allowed headers: *&lt;/li>
&lt;li>Exposed headers: *&lt;/li>
&lt;li>Max age: 0&lt;/li>
&lt;/ul>
&lt;p>Click out of the fields and the configuration will be saved automagically. (Little green ticks appear in the fields for some visual feedback.)&lt;/p>
&lt;h3 id="rails-setup">Rails setup&lt;/h3>
&lt;p>We can follow the Rails documentation for &lt;a href="https://guides.rubyonrails.org/active_storage_overview.html#setup">setting up ActiveStorage&lt;/a>, ensures you have the migrations for the required database tables installed and the framework is loaded in your application.&lt;/p>
&lt;p>Follow the rails docs &lt;a href="https://guides.rubyonrails.org/active_storage_overview.html#microsoft-azure-storage-service">for configuring &lt;code>config/storage.yml&lt;/code> with Azure&lt;/a>, and pulling &lt;code>azure-storage-blob&lt;/code> into your app. (In Rails 8.1 this will be &lt;code>azure-blob&lt;/code> instead, see &lt;a href="https://testdouble.com/insights/azure-blob-a-new-ruby-gem-for-azure-blob-storage">test double&amp;rsquo;s post on the subject for more information&lt;/a>) I suggest storing the key in Rails credentials (or however you inject secrets into your rails app), and creating a new block in &lt;code>storage.yml&lt;/code> for Azure storage. Using credentials per-environment makes using a different storage account for Staging &amp;amp; Production easy.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">azure_storage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">service&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AzureStorage&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">storage_account_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;%= Rails.application.credentials.dig(:azure_storage, :storage_account_name) %&amp;gt;&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">storage_access_key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %&amp;gt;&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;%= Rails.application.credentials.dig(:azure_storage, :container_name) %&amp;gt;&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Edit the credentials for the given environment (eg, &lt;code>bin/rails credentials:edit --environment=production&lt;/code>) and enter the values we got from Azure above:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">azure_storage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">storage_account_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;st123someappproduksth&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">storage_access_key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Qm9yZWQgeWV0PyBGdWNraW5nIGJhbGxhY2hlIGlubml0Lgo=&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;dragon-myapp-production-uksouth-activestorage&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Update the appropriate &lt;code>config/environments/*.rb&lt;/code> file for the environments you want to use this Azure storage, setting &lt;code>config.active_storage.service&lt;/code> to the key of the block in &lt;code>storage.yml&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">active_storage&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="ss">:azure_storage&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Deploy your changes, and you&amp;rsquo;re good to start using ActiveStorage to manage your uploaded files. Ensure the ActiveStorage JS is added to your frontend (depends on which asset pipeline flavour the app is configured to use, should be there by default) and you won&amp;rsquo;t be sending all files through your Rails backend, saves you some bandwidth and CPU cycles.&lt;/p></description></item><item><title>Programatically invoke rake task with --trace enabled</title><link>https://caiustheory.com/programatically-invoke-rake-task-with--trace-enabled/</link><pubDate>Tue, 01 Oct 2024 22:42:00 +0000</pubDate><guid>https://caiustheory.com/programatically-invoke-rake-task-with--trace-enabled/</guid><description>&lt;p>&lt;a href="https://ruby.github.io/rake/">Rake&lt;/a> is a Make-like program implemented in Ruby &lt;em>(to quote the website.)&lt;/em> It contains tasks written in ruby code you can invoke from the command line. These can run prequisite tasks first too, in this case we configure the &lt;code>setup&lt;/code> task to be invoked before the &lt;code>work&lt;/code> task is ever invoked.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">task&lt;/span> &lt;span class="ss">:setup&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Setting up&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">task&lt;/span> &lt;span class="ss">work&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="ss">:setup&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Doing work&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ rake work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Setting up
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Doing work
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Rake also supports &lt;code>--trace&lt;/code> as an argument which outputs a bunch of debugging information, allowing you to see which tasks have been executed in which order and how often they were invoked.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ rake --trace work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke work &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke setup &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute setup
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Setting up
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Doing work
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>From the &lt;code>--trace&lt;/code> output we can see calling the same task multiple times in the same rake process doesn&amp;rsquo;t execute the task multiple times, but it is invoked the correct number of times.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ rake --trace work setup work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke work &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke setup &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute setup
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Setting up
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Doing work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke setup
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke work
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For performance reasons (&lt;a href="https://rubyonrails.org">Rails&lt;/a> apps can take multiple seconds to start a new process), we might want to run multiple tasks within the same &lt;code>rake&lt;/code> process.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">task&lt;/span> &lt;span class="ss">:create_assets&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Created some assets&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We&amp;rsquo;re now stuck in a catch-22 from the shell in terms of tracing however, if we run both tasks in the same process we can only trace both, or trace neither.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ rake --trace create_assets work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke create_assets &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute create_assets
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Created some assets
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke work &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke setup &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute setup
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Setting up
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Doing work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ rake create_assets work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Created some assets
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Setting up
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Doing work
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If we&amp;rsquo;ve previously been calling multiple tasks in different commands and only tracing some of them, we want to maintain the same output in our CI system logs but also reap the performance benefit of not booting the app multiple times over. This means having tracing enabled for some tasks, but not others which we can&amp;rsquo;t do from the shell.&lt;/p>
&lt;p>Luckily there&amp;rsquo;s another mechanism to invoke multiple rake tasks, we define a new rake task that can then call the other rake tasks and setup tracing before calling the last one by &lt;a href="https://github.com/ruby/rake/blob/4538838a4b9d2cbfa1e231716a2183e65241b52e/lib/rake/application.rb#L613-L622">mimicking the internals of &lt;code>rake --trace&lt;/code>&lt;/a>.&lt;/p>
&lt;p>(&lt;code>Rake::Task.[]&lt;/code> lets you find rake tasks by their labels, and then &lt;code>Rake::Task#invoke&lt;/code> calls the code defined for the task as if you&amp;rsquo;d run &lt;code>rake whatever&lt;/code> on the cli.)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">task&lt;/span> &lt;span class="ss">:ci_perform&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Rake&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="no">Task&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;create_assets&amp;#34;&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">invoke&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Enable `--trace` programatically for remaining tasks invoked&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Rake&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">application&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">options&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">trace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kp">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Rake&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">application&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">options&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">backtrace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kp">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Rake&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">application&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">options&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">trace_output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="vg">$stderr&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Rake&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">verbose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kp">true&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Rake&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="no">Task&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;work&amp;#34;&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">invoke&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Et voila, we get our trace output for the &lt;code>work&lt;/code> task but not until that&amp;rsquo;s invoked.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">$ rake ci_perform
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Created some assets
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke work &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Invoke setup &lt;span class="o">(&lt;/span>first_time&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute setup
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Setting up
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">** Execute work
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Doing work
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Running OmniOS via UTM on Apple Silicon</title><link>https://caiustheory.com/running-omnios-via-utm-on-apple-silicon/</link><pubDate>Fri, 05 Jan 2024 01:00:00 +0000</pubDate><guid>https://caiustheory.com/running-omnios-via-utm-on-apple-silicon/</guid><description>&lt;p>Wanted to fire up &lt;a href="https://omnios.org/">OmniOS&lt;/a> to play with and didn&amp;rsquo;t have any spare x86 hardware to hand so decided to figure out running it in &lt;a href="https://getutm.app/">UTM&lt;/a> on Apple Silicon, meaning it needs emulation as OmniOS is x86 only.&lt;/p>
&lt;p>Grab the ISO from the &lt;a href="https://omnios.org/download.html">OmniOS downloads page&lt;/a>, I used the LTS release but the current stable should work too. Just make sure it&amp;rsquo;s the ISO version, not USB, etc.&lt;/p>
&lt;p>Open UTM and click &amp;ldquo;Create a New Virtual Machine&amp;rdquo;. Choose &amp;ldquo;Emulate&amp;rdquo; as we need a x86 VM on an aarch64 host. Choose &amp;ldquo;Other&amp;rdquo; for the Operating System, then select the iso file you downloaded above from the Browse… button.&lt;/p>
&lt;p>Make sure to leave the Hardware Architecture set to x86_64, but adjust the rest to what you require. OmniOS suggests 1GB ram minimum for VMs. Storage is suggested to be 8GB minimum.&lt;/p>
&lt;p>On the Summary screen check the &amp;ldquo;Open VM Settings&amp;rdquo; and click Save.&lt;/p>
&lt;p>On the Settings popover that appears, select Display from the sidebar and change the &amp;ldquo;Emulated Display Card&amp;rdquo; to &amp;ldquo;VGA&amp;rdquo;. This ensures we don&amp;rsquo;t get a black screen when booting.&lt;/p>
&lt;p>I then chose to make the VM appear as a separate host on my LAN, by changing &amp;ldquo;Network&amp;rdquo; -&amp;gt; &amp;ldquo;Network Mode&amp;rdquo; to &amp;ldquo;Bridged (Advanced)&amp;rdquo;. This isn&amp;rsquo;t required.&lt;/p>
&lt;p>Save the settings and boot the VM, now you can follow the &lt;a href="https://omnios.org/setup/freshinstall.html">OmniOS Installer Walk-Through&lt;/a> as normal.&lt;/p>
&lt;p>On the post-installation menu I chose &amp;ldquo;&lt;strong>C&lt;/strong>onfigure the installed OmniOS system&amp;rdquo;, then &amp;ldquo;&lt;strong>C&lt;/strong>onfigure Networking&amp;rdquo; and changed it from Static to DHCP, so it will pick up an IP at boot from my router.&lt;/p>
&lt;p>Reboot and Enjoy.&lt;/p>
&lt;p>&lt;img src="/2024-01-06-omnios-running-utm.png" alt="OmniOS boot menu inside a UTM window on a Mac">&lt;/p></description></item><item><title>Upgraded Dekoni Earpads for Sony WH-1000XM3 Headphones</title><link>https://caiustheory.com/upgraded-dekoni-earpads-for-sony-wh-1000xm3-headphones/</link><pubDate>Sun, 24 Dec 2023 15:09:00 +0000</pubDate><guid>https://caiustheory.com/upgraded-dekoni-earpads-for-sony-wh-1000xm3-headphones/</guid><description>&lt;p>Back in 2019 I picked up a pair of &lt;a href="https://www.sony.co.uk/electronics/headband-headphones/wh-1000xm3">Sony WH-1000XM3 Headphones&lt;/a> for using in the office. Very useful and work well in an office and on public transport. After a while I was finding my ears were getting quite hot when wearing them all day, especially on hotter days in the summer.&lt;/p>
&lt;p>The original earpads had a shiny synthetic surface, after some research I happened across Dekoni&amp;rsquo;s Synthetic Suede Earpads as a suggested upgrade for the XM3&amp;rsquo;s. Discovered &lt;a href="https://www.electromod.co.uk/">Electromod&lt;/a> are a UK business that imports them for sale here, and &lt;a href="https://www.electromod.co.uk/dekoni-choice-synthetic-earpads-for-sony-wh1000xm3-headphones">ordered them&lt;/a>. Arrived promptly, and an unrelated issue around payment was easily resolved by customer services. Would buy from them again without any worries.&lt;/p>
&lt;p>Fitting the earpads was pretty simple, the old pads lever off and the new pads are pressed into place. From memory I used a plastic spudger to pop the old pads off. The Synthetic Suede seals much better against my head, is cooler to the touch and doesn&amp;rsquo;t overheat in the same way. I&amp;rsquo;ve taken to wiping them off with a soft cloth occasionally to stop muck building up on them.&lt;/p>
&lt;p>Electromod also carry upgraded earpads for &lt;a href="https://www.electromod.co.uk/dekoni?category=earpads">many other headphones&lt;/a>, including Sony XM4/XM5 and Bose QC/700&amp;rsquo;s.&lt;/p></description></item><item><title>`asdf install ruby` on macOS</title><link>https://caiustheory.com/asdf-install-ruby-macos/</link><pubDate>Wed, 10 May 2023 21:03:53 +0000</pubDate><guid>https://caiustheory.com/asdf-install-ruby-macos/</guid><description>&lt;p>Installing ruby through &lt;a href="https://asdf-vm.com">asdf&lt;/a> on Apple Silicon Macs&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> will attempt to build a custom OpenSSL for each install because it can&amp;rsquo;t find OpenSSL from homebrew in &lt;code>/usr/local&lt;/code>, as that&amp;rsquo;s now installed in &lt;code>/opt/homebrew&lt;/code>. This means your &lt;code>brew update&lt;/code> no longer pulls in security fixes for your ruby runtimes, as well as wasting disk space.&lt;/p>
&lt;p>Ruby 2.6.10 &amp;amp; 2.7.x need OpenSSL 1.1, and are unsupported at time of publishing so you should really upgrade to ruby 3! (Tested with ruby 2.6.10 and 2.7.8 at time of publishing.)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">brew install openssl@1.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">RUBY_CONFIGURE_OPTS&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;--with-openssl-dir=&lt;/span>&lt;span class="k">$(&lt;/span>brew --prefix openssl@1.1&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> asdf install ruby 2.7.8
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ruby 3.0 and higher need OpenSSL 3.0+ so we follow the same override but with a different brew name. (Tested with ruby 3.1.4 and 3.2.2 at time of publishing.)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">brew install openssl@3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">RUBY_CONFIGURE_OPTS&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;--with-openssl-dir=&lt;/span>&lt;span class="k">$(&lt;/span>brew --prefix openssl@3&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> asdf install ruby 3.2.2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Also if you&amp;rsquo;re trying to install a version of ruby that exists in &lt;a href="https://github.com/rbenv/ruby-build">rbenv/ruby-build&lt;/a> &lt;code>master&lt;/code> branch, but not in the version of ruby-build &lt;a href="https://github.com/asdf-vm/asdf-ruby/blob/master/lib/utils.sh#L3">asdf-ruby plugin uses&lt;/a> you can override it with &lt;code>ASDF_RUBY_BUILD_VERSION=master&lt;/code> when running &lt;code>asdf ruby install x.y.z&lt;/code>. Pass as an extra envariable to the above commands.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>M1/M2 processors&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>@fediverse@twitter via ///</title><link>https://caiustheory.com/define.rental.yoga/</link><pubDate>Fri, 04 Nov 2022 22:47:00 +0000</pubDate><guid>https://caiustheory.com/define.rental.yoga/</guid><description>&lt;p>An amusing idea from &lt;a href="https://mastodon.xyz/@xor">&lt;code>@xor@mastodon.xyz&lt;/code>&lt;/a> for Mastodon instance names (which form part of your username) has been taking three word phrases from Moby Dick and trying to find available domain names, so you could host your instance at &lt;code>famous.whaling.house&lt;/code> for example.&lt;/p>
&lt;p>Parker has since &lt;a href="https://parkerhiggins.net/2022/11/public-sub-domains">blogged his idea and some examples&lt;/a> which is well worth a read and explains it in more depth, as well as explaining how he did and linking to the script if you want a go.&lt;/p>
&lt;blockquote>
&lt;p>Many Mastodon instances are on subdomains, and since the early days weirder new-style TLDs have been de rigueur. (The flagship has always been at a .social!) So I set out to find three-word phrases where the third word is a 4+-letter top-level domain, using as my first source text Moby Dick.&lt;/p>
&lt;/blockquote>
&lt;p>Re-reading through the thread on mastodon again, I spotted the following reply from &lt;a href="https://mastodon.social/@knowtheory">&lt;code>@knowtheory@mastodon.social&lt;/code>&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>Ok. Now map them on what three words&lt;/p>
&lt;p>&lt;em>— &lt;a href="https://mastodon.social/@knowtheory/109282602341495412">https://mastodon.social/@knowtheory/109282602341495412&lt;/a>&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>Now whilst I don&amp;rsquo;t think what3words is beneficial in their current form&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>, they are definitely a great service for comedy purposes. Given they also have three word phrases, and can point to a location anywhere in the world… what&amp;rsquo;s the funniest location we could put a Mastodon instance on and join the fediverse with?&lt;/p>
&lt;p>Say, what&amp;rsquo;s the Twitter HQ location on W3W? Searching for &amp;ldquo;Twitter&amp;rdquo; suggests &amp;ldquo;Twitter HQ, Market Street, San Francisco&amp;rdquo;, clicking that shows Twitter&amp;rsquo;s W3W location as &lt;a href="https://what3words.com/define.rental.yoga">&lt;code>///define.rental.yoga&lt;/code>&lt;/a>.&lt;/p>
&lt;img src="/2022-11-04-w3w-define-rental-yoga.png" alt="Screenshot of what3words map showing Twitter HQ at define.rental.yoga" class="center">
&lt;p>A quick search on the Wikipedia page for &lt;a href="https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains">Internet Top Level Domains&lt;/a> reveals that &lt;code>.yoga&lt;/code> is a valid TLD. Further searching on a couple of domain registrars shows that &lt;code>rental.yoga&lt;/code> is also available! For a mere £32/year, and hosting a mastodon instance there you could be &lt;code>@you@define.rental.yoga&lt;/code> and declare that you haven&amp;rsquo;t left Twitter!&lt;/p>
&lt;p>&lt;em>For some reason this amused me enough to blog about it. I have not registered &lt;code>rental.yoga&lt;/code>. Who will? 🙃&lt;/em>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>what3words has issues when it comes to critical safety scenarios, when it involves humans reading the phrases to each other. See &lt;a href="https://cybergibbons.com/security-2/why-what3words-is-not-suitable-for-safety-critical-applications/">https://cybergibbons.com/security-2/why-what3words-is-not-suitable-for-safety-critical-applications/&lt;/a> for more information. And yet they appear to pay Emergency Services to use and advertise their proprietary service. 🤨&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>iLO 4 Firmware Upgrade</title><link>https://caiustheory.com/ilo-4-firmware-upgrade/</link><pubDate>Sat, 02 Jul 2022 11:01:01 +0000</pubDate><guid>https://caiustheory.com/ilo-4-firmware-upgrade/</guid><description>&lt;p>HP Microserver Gen8 machines have a &lt;a href="https://en.wikipedia.org/wiki/HP_Integrated_Lights-Out">HP iLo&lt;/a> 4 built in for remote hands management. These are effectively a separate, embedded computer inside the server&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>, which also means it has its own software (firmware) running on it and needs updating separately.&lt;/p>
&lt;p>HP are still releasing firmware updates for the iLo 4, and whilst it&amp;rsquo;s possible to update them from inside the host OS on the server, you can also do it by uploading the firmware directly to the iLO. I prefer this method as my servers are almost never running the correct operating system to update from the host&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>The easiest way to get ahold of the firmware is to extract it from the Red Hat linux host package, we&amp;rsquo;re after a &lt;code>.bin&lt;/code> file inside the &lt;code>.rpm&lt;/code> package HP make available for downloading.&lt;/p>
&lt;p>At the time of writing the latest firmware release is v2.8.0, released 2022-04-08, available &lt;a href="https://support.hpe.com/connect/s/softwaredetails?language=en_US&amp;amp;softwareId=MTX_d08e4968119e4737b8549928c2">on HP&amp;rsquo;s support site here&lt;/a> (no login required). Click &amp;ldquo;View Download Files (2)&amp;rdquo; and then pick the one ending in &lt;code>.rpm&lt;/code> (&lt;code>firmware-ilo4-2.80-1.1.i386.rpm&lt;/code> at time of writing.)&lt;/p>
&lt;p>Once downloaded, we can unpack the &lt;code>rpm&lt;/code> using the &lt;code>rpm2cpio&lt;/code> tool and then &lt;code>cpio&lt;/code> to output the files on disk for us.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">rpm2cpio firmware-ilo4-2.80-1.1.i386.rpm &lt;span class="p">|&lt;/span> clio -idmv
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The file we&amp;rsquo;re after is nested inside a few directories in the unpacked directory. You can find it under &lt;code>usr/lib/i386-linux-gnu/firmware-ilo4-2.80-1.1/&lt;/code> named &lt;code>ilo4_280.bin&lt;/code> (at time of writing. Version numbers might differ in future.)&lt;/p>
&lt;p>Once you have that &lt;code>bin&lt;/code> file on disk, go to your iLO web interface and login. Navigate to &amp;ldquo;Administration&amp;rdquo; in the sidebar, then select the &amp;ldquo;Firmware&amp;rdquo; tab. Pick the &lt;code>bin&lt;/code> file from the file picker and click Upload.&lt;/p>
&lt;p>Wait for flashing to complete and the iLO to restart. If you&amp;rsquo;ve upgraded from &amp;lt; 2.78 then you&amp;rsquo;ll get a new UI as part of the upgrade which looks better and works just as well as the old one. It also adds new functionality, like a HTML5 remote console rather than having to download a &lt;code>.jar&lt;/code> file to take remote control of the machine.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Out the box at least. The iLo can be configured to share eth0 with the host instead I believe.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>I think both Windows and Red Hat linux are supported for this.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Shawbury 10km 2021</title><link>https://caiustheory.com/shawbury-10km-2021/</link><pubDate>Sat, 25 Sep 2021 16:05:00 +0000</pubDate><guid>https://caiustheory.com/shawbury-10km-2021/</guid><description>&lt;p>RAF Shawbury host an annual 10km running race, and I entered this time because a friend suggested it as an event to aim for over the summer. Given the run is along runways/taxiways it&amp;rsquo;s going to be one of the flattest courses on offer. Seemed like a good idea at the time.&lt;/p>
&lt;p>Got there with plenty of time to register, figure out where the important things—coffee &amp;amp; ice cream vans—were and go for a nervous wee. Decided to start a workout on my watch early, set it to 10(km, I thought) and paused it straight away to wait for the gun. Stood around for another ~5 minutes waiting for the gun to go. Unpaused the watch as I went across the line and we were off.&lt;/p>
&lt;p>Started near the front of the midfield and set out at a pace that I thought was around 10:20/mile, didn&amp;rsquo;t pay too much attention to people coming past me as it was a mass start rather than paced start. Kept pace with some absolute legend running in an Elephant costume (I&amp;rsquo;d overheard they were targeting a 56 minute finish, something I later realised to be a joke.) Easy enough route, round a taxiway and down the main runway to start.&lt;/p>
&lt;p>Mile in, feeling good, lots of energy. Watch buzzes the mile pace … 10:55/mile. Yeesh, that&amp;rsquo;s way slower than I meant to start, and the rolling mile display hadn&amp;rsquo;t displayed anything until I&amp;rsquo;d hit the first mile mark. Oops, time to turn the pace up slightly. Kept going until the rolling mile showed under 10:00/mile, second mile came in at 9:27/mile and then tried to keep it under 10:00/mile whilst not blowing the heart rate up too much.&lt;/p>
&lt;p>Marshals around the course were lovely and supportive, although compared to a road 10km through town where people come out of their houses and cheer it felt quite quiet as an event. Seeing someone every time a corner occurred was a welcome sight though, and the water stop was quite well placed just before the halfway mark.&lt;/p>
&lt;p>Hit 3.1 miles in around 31-32 minutes which was on pace, legs were feeling okay and I took some water on board whilst running. Second half of the course I started using other people to pace myself, I&amp;rsquo;d pick someone 50-100 meters ahead who didn&amp;rsquo;t appear to be vanishing from me and then try and slowly overhaul them without increasing the heart rate too much.&lt;/p>
&lt;p>Around the 5 mile mark (~50 minutes) I wondered if I could be on for an hour finish. Also realised as the watch buzzed &amp;ldquo;Halfway there!&amp;rdquo; that it was set to a 10 mile run. Useful. Heart rate was creeping up to maximum, legs were starting to ache and the ball of my left foot was starting to complain about repeatedly slamming into the tarmac. Tried elongating my stride and springing off each step a bit more consciously, also hit the point of talking to myself which is a good sign I&amp;rsquo;m starting to tire and need to start concentrating on what I&amp;rsquo;m doing form-wise.&lt;/p>
&lt;p>Saw the 1km board, then the 500m board and was looking for a 250m board to kick harder from. Sailed past a friend who had already finished about the 200m mark and was really trying not to blow the heart rate through the roof. Found a 150m board—complete with amusingly sarcastic comment along the lines of &amp;ldquo;ooh, time to put some effort in&amp;rdquo;—and ramped the pace up slightly. Mindful of keeping the heart rate under control still, pushed a little too high according to my stats afterwards but felt okay doing so for a few seconds.&lt;/p>
&lt;p>Crossed the line with a gun time of 1:00:51. Super chuffed I nearly dipped under the 1 hour mark, expected to be around 1:04 having done a 1:06:30 cross-country 10km earlier in the summer. I &lt;strong>really&lt;/strong> must remember not to mess around with my equipment before events though, only make changes before going for training runs because something is &lt;em>always&lt;/em> setup wrong.&lt;/p>
&lt;p>In this case I&amp;rsquo;d switched from kilometres to miles for running events, reset my watch yesterday so it had no music/podcasts on to listen to and also changed the display for a running workout, crucially removing the average pace of the whole activity. What I hadn&amp;rsquo;t foreseen making those changes was I&amp;rsquo;d have to wait a mile before I got &lt;em>any&lt;/em> pace feedback from the watch.&lt;/p>
&lt;p>I also discovered uploading straight to &lt;a href="https://www.strava.com/athletes/2295429">Strava&lt;/a> (through &lt;a href="https://www.rungap.com">Rungap&lt;/a>) that pausing the watch ahead of time completely screws up the timings. Strava reckoned I&amp;rsquo;d done an 18:25/mile first mile! I knew it was slow, but it wasn&amp;rsquo;t &lt;em>that&lt;/em> slow. Ended up exporting a GPX and removing the first 6 minutes stood around with it paused to make Strava happy about the timings.&lt;/p>
&lt;p>&lt;a href="https://www.strava.com/activities/6016842101">Race on Strava&lt;/a>&lt;/p></description></item><item><title>Fix Edgerouter DHCP ? entries</title><link>https://caiustheory.com/fix-edgerouter-dhcp-entries/</link><pubDate>Sun, 14 Mar 2021 15:55:00 +0000</pubDate><guid>https://caiustheory.com/fix-edgerouter-dhcp-entries/</guid><description>&lt;p>Occasionally I end up with devices on the local network that don&amp;rsquo;t emit their hostname over DHCP, so when listing the current leases on the EdgeRouter&amp;rsquo;s cli, they just appear as &amp;ldquo;?&amp;rdquo;.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> These usually just irritate me, but occasionally when I&amp;rsquo;m looking for a machine on the network it means I can&amp;rsquo;t find it and end up poking the different &amp;ldquo;?&amp;rdquo; IPs using &lt;code>nmap&lt;/code> or &lt;code>ssh&lt;/code> to discover which machines they are.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ show dhcp leases
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">IP address Hardware Address Lease expiration Pool Client Name
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">---------- ---------------- ---------------- ---- -----------
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.34 a8:1d:16:74:xx:yy 2021/03/14 16:38:27 trusted ?
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.40 b8:27:eb:c5:xx:yy 2021/03/14 16:36:13 trusted picontrol1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.46 a8:1d:16:75:xx:yy 2021/03/14 16:37:48 trusted ?
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.93 14:f6:d8:53:xx:yy 2021/03/14 16:40:29 trusted ?
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The EdgeRouter lets me assign static entries in the DHCP subnet, which solves the problem of knowing which hostnames they are, but also pins those devices to (effectively) static IPs within the subnet which leads to me having to know which IPs are free when I assign them, etc. Avoiding that is why I have DHCP on the local network.&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;p>Provided the EdgeRouter is configured to use &lt;a href="https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html">dnsmasq&lt;/a> to provide DHCP services&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>, you can lean on the &lt;code>dhcp-host&lt;/code> option in the dnsmasq configuration to assign a hostname based on MAC address, without prescribing a specific IP address for the machine. This solves the issue of &amp;ldquo;?&amp;rdquo; devices showing up in &lt;code>show dhcp leases&lt;/code>, whilst also allowing dynamic IP assignment.&lt;/p>
&lt;p>You&amp;rsquo;ll need to know the MAC address in question, and pick a hostname to be assigned to the machine. You&amp;rsquo;ll then want to inject these through dnsmasq&amp;rsquo;s configuration file, which &lt;code>set service dns forwarding options xxx&lt;/code> nicely injects into on the EdgeRouter.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ configure
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> service dns forwarding options &lt;span class="s2">&amp;#34;dhcp-host=14:f6:d8:53:xx:yy,cb1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> service dns forwarding options &lt;span class="s2">&amp;#34;dhcp-host=a8:1d:16:75:xx:yy,cb3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> service dns forwarding options &lt;span class="s2">&amp;#34;dhcp-host=a8:1d:16:74:xx:yy,cb2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then follow the usual &lt;code>compare&lt;/code>, &lt;code>commit&lt;/code>, verify your DNS/DHCP still works, &lt;code>save&lt;/code> dance to apply &amp;amp; persist the changes.&lt;/p>
&lt;p>Now when you login to the router and list the current DHCP leases, you&amp;rsquo;ll see the hostnames available - and you can now lookup the machines in local DNS via their hostname too. 🎉&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ show dhcp leases
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">IP address Hardware Address Lease expiration Pool Client Name
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">---------- ---------------- ---------------- ---- -----------
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.34 a8:1d:16:74:xx:yy 2021/03/14 16:38:27 trusted cb2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.40 b8:27:eb:c5:xx:yy 2021/03/14 16:36:13 trusted picontrol1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.46 a8:1d:16:75:xx:yy 2021/03/14 16:37:48 trusted cb3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">10.0.0.93 14:f6:d8:53:xx:yy 2021/03/14 16:40:29 trusted cb1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>On my network currently these are Chromebooks, and Sonos speakers. I&amp;rsquo;ve also observed native SmartOS Zones behaving like this previously (I think they might have fixed this now.) I believe the device fails to send the current hostname (option 12) in either the DHCPDISCOVER or DHCPREQUEST packets.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>Also, if I assign static host mappings to a device they vanish entirely from &lt;code>show dhcp leases&lt;/code>, which stops me being lazy and checking one place to figure out where a device is.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>To find out if you&amp;rsquo;re using dnsmasq for DHCP, check &lt;code>show service dhcp-server use-dnsmasq&lt;/code> returns &amp;ldquo;enable&amp;rdquo;&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Cleaning BODUM Bistro Coffee Grinder</title><link>https://caiustheory.com/cleaning-bodum-bistro-coffee-grinder/</link><pubDate>Sun, 17 Jan 2021 11:41:00 +0000</pubDate><guid>https://caiustheory.com/cleaning-bodum-bistro-coffee-grinder/</guid><description>&lt;p>I&amp;rsquo;ve owned a &lt;a href="https://www.bodum.com/gb/en/10903-01uk-3-bistro">BODUM Bistro Coffee Grinder&lt;/a> for a number of years, and aside from occasionally running rice through to clean the grinding surfaces haven&amp;rsquo;t had any issues with it. Recently bought some new beans which are much oilier than ones I usually get, and after running most of them through ended up with the grinder failing to work.&lt;/p>
&lt;p>The failure was the mechanism sounding like it was okay for roughly a second, then the motor straining under load before what sounded like plastic gears jumping teeth. At this point I turned it off. Running it with an empty hopper worked fine, adding anything (either beans or ground coffee) to the hopper caused the load issue. On the third attempt it also had stopped self-feeding from the hopper, and trying to gently push beans/grounds through caused the stoppage above.&lt;/p>
&lt;p>&lt;a href="https://www.youtube.com/user/HagmanDavid">David Hagman&lt;/a> has previously torn down his grinder and posted a &lt;a href="https://www.youtube.com/watch?v=w_Kl8Aw8iDU">video on YouTube showing the internals&lt;/a>. I couldn&amp;rsquo;t see any obvious part of the internals that would be related to the failure I was experiencing, so I decided to start with cleaning it out and then continue with a strip down if that didn&amp;rsquo;t reveal anything.&lt;/p>
&lt;p>To start with the hopper came off, then the top half of the burr grinder lifts out vertically leaving a worm screw standing proud. I first started gently tapping the grinder unit upside down to free any stuck coffee, then escalated to a small bottle brush. There was still enough grounds stuck around the base of the screw mechanism I couldn&amp;rsquo;t reach with a narrow brush, so I switched to a bamboo barbequeue stick to loosen grounds and then tip them out.&lt;/p>
&lt;p>After clearing out most of the base of the worm gear, whilst I had the unit upside down tapping out the loosened grounds I looked up the chute the grounds fall down into the jar normally to find it was blocked &lt;strong>solid&lt;/strong> with ground coffee. Some gentle &lt;a href="https://www.youtube.com/watch?v=GSLTfRShSHY">rodding with the skewer&lt;/a> to break it up and eventually I could see from the grinder mechanism through to the end of the chute.&lt;/p>
&lt;p>Once that was clear and everything removable had been thoroughly cleaned and dried, I reassembled and ran rice through it a few times starting with a really coarse grind and fed the result back through the hopper, getting finer each grind. Grinder now works flawlessly, and I guess lesson learned about checking the chute to make sure it&amp;rsquo;s clear more frequently.&lt;/p></description></item><item><title>Disable Google Autoupdater on macOS</title><link>https://caiustheory.com/disable-google-autoupdater-on-macos/</link><pubDate>Mon, 14 Dec 2020 16:14:53 +0000</pubDate><guid>https://caiustheory.com/disable-google-autoupdater-on-macos/</guid><description>&lt;p>From reading &lt;a href="https://chromeisbad.com">Chrome is Bad&lt;/a>, it seems in some situations the updater (also known as keystone) can chew up CPU cycles. Whilst I&amp;rsquo;m not 100% convinced keystone continuously chews CPU, its launchctl configuration suggests it runs at least once an hour. Given I don&amp;rsquo;t use Chrome as my main browser, this is undesirable behaviour for me.&lt;/p>
&lt;p>With that in mind, I&amp;rsquo;ve decided to disable the background services rather than delete Chrome entirely. (I need it occasionally.) Stopping/unloading the services and fettling the config files to do nothing achieves this aim (and stops Chrome re-enabling them next launch), whilst leaving Chrome fully functional when needed.&lt;/p>
&lt;ol start="0">
&lt;li>
&lt;p>Unload the currently loaded services&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">launchctl unload -w ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">launchctl unload -w ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Empty the config files, so if launchd ever tries to launch them they&amp;rsquo;ll just error out&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &amp;gt; ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &amp;gt; ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Change ownership and permissions of these files so only root can write to the files&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">chmod &lt;span class="m">644&lt;/span> ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">chmod &lt;span class="m">644&lt;/span> ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chown root ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo chown root ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Now when I want to update Chrome once in a blue moon when I need it, I can navigate to &lt;a href="chrome://settings/help">chrome://settings/help&lt;/a> to update (or from the UI, Chrome -&amp;gt; About Chrome.)&lt;/p></description></item><item><title>Let's Peek: A tale of finding "Waypoint"</title><link>https://caiustheory.com/lets-peek/</link><pubDate>Thu, 15 Oct 2020 20:00:00 +0100</pubDate><guid>https://caiustheory.com/lets-peek/</guid><description>&lt;p>Following a product launch at work earlier this year, I theorised if someone was watching the published lists of SSL Certificates they could potentially sneak a peak at things before they were publicised. Probably far too much noise to monitor continuously, but as a potential hint towards naming of things with a more targeted search it might be useful. Sites like &lt;a href="https://crt.sh/">https://crt.sh/&lt;/a> and &lt;a href="https://censys.io/certificates">https://censys.io/certificates&lt;/a> make these logs searchable and queryable.&lt;/p>
&lt;p>Fast forward to this week, where at &lt;a href="https://digital.hashiconf.com/">HashiConf Digital&lt;/a> &lt;a href="https://hashicorp.com/">HashiCorp&lt;/a> are announcing two new products, which they&amp;rsquo;ve been teasing for a month or so. Watching &lt;a href="https://boundaryproject.io/">Boundary&lt;/a> get announced in the HashiConf opening keynote I then wondered what the second project might be called.&lt;/p>
&lt;p>I&amp;rsquo;ve spent a chunk of the last month looking at various HashiCorp documentation for their projects, and I noticed they have a pattern recently of using &lt;code>&amp;lt;name&amp;gt;project.io&lt;/code> as the product websites. The newly announced Boundary also fits this pattern.&lt;/p>
&lt;p>🤔 Could I figure out the second product name 24 hours before public release? &lt;a href="https://twitter.com/Caius/status/1316435256875143168">Amazingly, yes&lt;/a>! 🎉&lt;/p>
&lt;p>Searching at random for all certificates issued for &lt;code>*project.io&lt;/code> was probably going to be a bit futile, so to narrow the search space slightly I started by looking at when &lt;code>boundaryproject.io&lt;/code> had its certificate issued, and who by. The list of things I spotted were:&lt;/p>
&lt;ul>
&lt;li>Common name is &amp;ldquo;boundaryproject.io&amp;rdquo;&lt;/li>
&lt;li>Issued by LetsEncrypt (no real surprise there)&lt;/li>
&lt;li>Issued on 2020-09-23&lt;/li>
&lt;li>Leaf certificate&lt;/li>
&lt;li>Not yet expired (still trusted)&lt;/li>
&lt;li>No alternate names in the certificate&lt;/li>
&lt;/ul>
&lt;p>Loading up &lt;a href="https://censys.io/certificates">https://censys.io/certificates&lt;/a> and building a query for this, resulted in a regexp lookup against the common name, and an issued at date range of 10 days, just before and a week after the boundary certificate issued date.&lt;/p>
&lt;pre>&lt;code>parsed.subject.common_name:/[a-z]+project\.io/ AND
parsed.issuer.organization.raw:&amp;quot;Let's Encrypt&amp;quot; AND
parsed.validity.start:[&amp;quot;2020-09-20&amp;quot; TO &amp;quot;2020-09-30&amp;quot;] AND
tags.raw:&amp;quot;leaf&amp;quot; AND
tags.raw:&amp;quot;trusted&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>(&lt;a href="https://censys.io/certificates?q=parsed.subject.common_name%3A%2F%5Ba-z%5D%2Bproject%5C.io%2F+AND+parsed.issuer.organization.raw%3A%22Let%27s+Encrypt%22+AND+tags.raw%3A%22leaf%22+AND+tags.raw%3A%22trusted%22+AND+parsed.validity.start%3A%5B%222020-09-20%22+TO+%222020-09-30%22%5D">Run the search yourself&lt;/a>)&lt;/p>
&lt;p>Searching brought back a couple of pages of results, I scanned them by eye and copied out the ones that only had the single name in the certificate which resulted in the following shortlist:&lt;/p>
&lt;ul>
&lt;li>&lt;code>boundaryproject.io&lt;/code>&lt;/li>
&lt;li>&lt;code>essenceproject.io&lt;/code>&lt;/li>
&lt;li>&lt;code>lumiereproject.io&lt;/code>&lt;/li>
&lt;li>&lt;code>techproject.io&lt;/code>&lt;/li>
&lt;li>&lt;code>udproject.io&lt;/code>&lt;/li>
&lt;li>&lt;code>vesselproject.io&lt;/code>&lt;/li>
&lt;li>&lt;code>waypointproject.io&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>We already know about Boundary, so the fact I found it in our list suggests the query &lt;em>might&lt;/em> have captured the new product site too. Loading all these sites in a web browser showed some had password protection on them (ooh!) and some just plain didn’t load (ooh!), and some others were blatently other things (boo!). Removing the latter ones left us with a much shorter list:&lt;/p>
&lt;ul>
&lt;li>&lt;code>essenceproject.io&lt;/code>&lt;/li>
&lt;li>&lt;code>udproject.io&lt;/code>&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/li>
&lt;li>&lt;code>waypointproject.io&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>All domains on the internet have to point somewhere, using DNS records. On a hunch I looked up a couple of the existing HashiCorp websites to see if they happened to all point at the same IP Address(es).&lt;/p>
&lt;pre tabindex="0">&lt;code>$ host boundaryproject.io
boundaryproject.io has address 76.76.21.21
$ host nomadproject.io
nomadproject.io has address 76.76.21.21
$ host hashicorp.com | head -1
hashicorp.com has address 76.76.21.21
&lt;/code>&lt;/pre>&lt;p>Ah ha, now I wonder if any of the shortlist also points to &lt;code>76.76.21.21&lt;/code> 🤔&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;pre tabindex="0">&lt;code>$ host essenceproject.io | head -1
essenceproject.io has address 198.185.159.145
$ host udproject.io | head -1
udproject.io has address 137.74.116.3
$ host waypointproject.io
waypointproject.io has address 76.76.21.21
&lt;/code>&lt;/pre>&lt;p>🎉 Excellent, &lt;a href="https://waypointproject.io">https://waypointproject.io&lt;/a> was a password protected site pointed at HashiCorp&amp;rsquo;s IP address 🎉&lt;/p>
&lt;p>I then wondered if I could verify this somehow ahead of waiting for the second keynote. I firstly &lt;a href="https://twitter.com/Caius/status/1316435256875143168">tweeted about it&lt;/a> but didn&amp;rsquo;t name Waypoint explicitly, just hid &amp;ldquo;way&amp;rdquo; and &amp;ldquo;point&amp;rdquo; in the tweet. I got a reply from &lt;a href="https://twitter.com/ksatirli/status/1316435508046815234">@ksatirli&lt;/a> which suggested it was correct (and then later &lt;a href="https://twitter.com/mitchellh/status/1316468703584645121">@mitchellh&lt;/a> confirmed it.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>)&lt;/p>
&lt;p>HashiCorp also does a lot in public, and all the source code and related materials are on GitHub so perhaps some of their commit messages or marketing sites will contain reference to Waypoint. One github search later across their organisation: &lt;a href="https://github.com/search?q=org%3Ahashicorp+waypoint&amp;amp;type=issues">https://github.com/search?q=org%3Ahashicorp+waypoint&amp;amp;type=issues&lt;/a> and I&amp;rsquo;d discovered a commit in the newly-public &lt;code>hashicorp/boundary-ui&lt;/code> repo which references Waypoint: &lt;a href="https://github.com/hashicorp/boundary-ui/commit/346f76404d9a0c90dedbccdd3d2c228572eb5ec1">346f76404&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>chore: tweak colors to match waypoint and for a11y&lt;/p>
&lt;/blockquote>
&lt;p>Good enough for me, now to wait and see what the project is for. Given it&amp;rsquo;s now all announced and live, you can just visit &lt;a href="https://waypointproject.io">https://waypointproject.io&lt;/a> to find out! (It&amp;rsquo;s so much cooler/useful than I&amp;rsquo;d hoped for.)&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>I so hope whoever registered this was going for UDP in the name, rather than UD Project.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>I&amp;rsquo;m a massive fan of IP address related quirks. Facebook&amp;rsquo;s IPv6 address contains &lt;code>face:b00c&lt;/code> for example. A nice repeating &lt;code>76.76.21.21&lt;/code> is almost IPv4 art somehow.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>Secrets are more fun when they are kept secret. 🥳&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Tailscale, RFC1918, and DNS Rebinding Protection</title><link>https://caiustheory.com/tailscale-rfc1918-and-dns-rebinding-protection/</link><pubDate>Thu, 16 Jul 2020 21:00:00 +0100</pubDate><guid>https://caiustheory.com/tailscale-rfc1918-and-dns-rebinding-protection/</guid><description>&lt;p>&lt;strong>Edit:&lt;/strong> &lt;em>Originally this post was written to be a workaround for Tailscale routing all DNS traffic over its own link when you configured it to push out existing DNS Server IPs. This turned out to be a bad assumption on my part. Thanks to &lt;a href="https://twitter.com/apenwarr">apenwarr&lt;/a> for helping me understand that shouldn&amp;rsquo;t be the case, and encouraging me to debug it properly rather than making assumptions.&lt;/em>&lt;/p>
&lt;p>&lt;em>Naturally it turned out to be a &lt;a href="https://www.urbandictionary.com/define.php?term=pebkac">PEBKAC&lt;/a>. I&amp;rsquo;d pushed out &lt;code>162.159.25.4&lt;/code> as the DNS Server IP which is a nameserver rather than a forwarder. This in turn meant people were getting empty answers back to DNS queries, which stopped once they quit tailscale. (Go figure, Tailscale removes the resolver from the network stack when it quits.) The post has been updated to remove that invalid assumption. 🤦🏻‍♂️&lt;/em>&lt;/p>
&lt;p>Imagine we have a fleet of machines sat in a private network somewhere on a &lt;code>172.16.20.20/24&lt;/code> IP range, with entries pointing at them published on public DNS servers. Eg, &lt;code>dig +short workhorse.fake.tld&lt;/code> returns &lt;code>172.16.20.21&lt;/code>.&lt;/p>
&lt;p>Initially this all works swimmingly, until someone comes along that is using a DNS forwarder that with DNS rebinding protection enabled. Daniel Miessler has a &lt;a href="https://danielmiessler.com/blog/dns-rebinding-explained/">wonderfully succinct explanation on his blog&lt;/a> about DNS Rebinding attacks, but to protect against it you stop your resolver returning answers to DNS queries from public servers which resolve to IP addresses within standard internal network ranges. (ie, &lt;a href="https://www.ietf.org/rfc/rfc1918.txt">rfc1918&lt;/a>.)&lt;/p>
&lt;p>This means for those users they can successfully connect to our Tailscale network and access everything by IPs directly, but can&amp;rsquo;t access any of the internal infrastructure by hostname. eg, &lt;code>dig +short workhorse.fake.tld&lt;/code> will return an empty answer for them.&lt;/p>
&lt;p>Once we figured out the root cause of that, for workarounds we figured we could either run a DNS forwarder within our own infrastructure, or get all our staff to change their home DNS settings and hope they were never on locked down networks ever again.&lt;/p>
&lt;p>We chose the former, and thankfully &lt;a href="http://www.thekelleys.org.uk/dnsmasq/doc.html">dnsmasq&lt;/a> is really easy to configure in this fashion and we already have a node which is acting as the tailscale subnet relay, so we dropped the following config in &lt;code>/etc/dnsmasq.conf&lt;/code> on there:&lt;/p>
&lt;pre tabindex="0">&lt;code># Only listen for requests from VPN/local for debugging
interface=tailscale0
interface=lo
# Google DNS
server=8.8.8.8
server=8.8.4.4
# Quad9
server=9.9.9.9
# Cloudflare
server=1.1.1.1
server=1.0.0.1
# Race all servers to see which wins
all-servers
# Try and stop DNS rebinding, except where we expect it to happen
bogus-priv
stop-dns-rebind
rebind-localhost-ok
rebind-domain-ok=/fake.tld/
domain-needed
filterwin2k
no-poll
no-resolv
cache-size=10000
&lt;/code>&lt;/pre>&lt;p>One quick puppet run later, and our Tailscale subnet relays are happily running both tailscale and dnsmasq, serving out answers as fast as they can to other Tailscale nodes. Add port 53 to the &lt;a href="https://www.tailscale.com/kb/1018/acls">Tailscale ACL&lt;/a> and away we went.&lt;/p></description></item><item><title>RSpec Given/When/Then with symbols</title><link>https://caiustheory.com/rspec-given/when/then-with-symbols/</link><pubDate>Wed, 22 Apr 2020 18:30:00 +0100</pubDate><guid>https://caiustheory.com/rspec-given/when/then-with-symbols/</guid><description>&lt;p>Having a need to write some BDD-esque tests without the need of putting them in front of non-technical people, I was recently playing around with &lt;a href="https://relishapp.com/rspec/rspec-rails/docs/feature-specs/feature-spec">rspec feature specs&lt;/a>. Where I&amp;rsquo;ve used these previously we&amp;rsquo;ve eventually run into curation issues where the specs are outdated, brittle and require so much maintenance we&amp;rsquo;ve generally ended up lobbing cucumber into the project as a stopgap.&lt;/p>
&lt;p>This is due to ending up with feature specs like the following, which lead you to having to parse the code mentally to work out what it&amp;rsquo;s testing:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="no">RSpec&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">feature&lt;/span> &lt;span class="s2">&amp;#34;Admin: Posts&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scenario&lt;/span> &lt;span class="s2">&amp;#34;Authoring a post&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="ss">:user&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:admin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">login_as&lt;/span> &lt;span class="vi">@user&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">visit&lt;/span> &lt;span class="n">new_admin_post_path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fill_in&lt;/span> &lt;span class="s2">&amp;#34;Title&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">with&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;RSpec feature specs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fill_in&lt;/span> &lt;span class="s2">&amp;#34;Body&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">with&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Some piffle about feature specs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click_on&lt;/span> &lt;span class="s2">&amp;#34;Publish!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">visit&lt;/span> &lt;span class="n">root_url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">expect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to&lt;/span> &lt;span class="n">have_content&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;RSpec feature specs&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After some reading around, I eventually stumbled back across &lt;a href="https://www.futurelearn.com/info/blog/how-we-write-readable-feature-tests-with-rspec">this idea from Future Learn&lt;/a> where they lay out the above test by splitting it into private methods within the feature block, but leaving it more readable to future readers. I then found &lt;a href="https://www.madetech.com/blog/feature-testing-with-rspec">Made Tech&amp;rsquo;s take on this same idea&lt;/a>, and riffing off the both of them ended up with the following instead:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="no">RSpec&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">feature&lt;/span> &lt;span class="s2">&amp;#34;Admin: Posts&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scenario&lt;/span> &lt;span class="s2">&amp;#34;Authoring a post&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">given_i_am_logged_in_as_an_admin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">when_i_publish_a_new_post&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">then_i_see_the_post_on_the_homepage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kp">protected&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">given_i_am_logged_in_as_an_admin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="ss">:user&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:admin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">login_as&lt;/span> &lt;span class="vi">@user&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">when_i_publish_a_new_post&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">visit&lt;/span> &lt;span class="n">new_admin_post_path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fill_in&lt;/span> &lt;span class="s2">&amp;#34;Title&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">with&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;RSpec feature specs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fill_in&lt;/span> &lt;span class="s2">&amp;#34;Body&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">with&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Some piffle about feature specs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click_on&lt;/span> &lt;span class="s2">&amp;#34;Publish!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">then_i_see_the_post_on_the_homepage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">visit&lt;/span> &lt;span class="n">root_url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">expect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to&lt;/span> &lt;span class="n">have_content&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;RSpec feature specs&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now this is fine, but writing lots_of_names_with_underscores_in_is_a_trifle &lt;strong>irritating&lt;/strong>. Now I remember &lt;a href="https://weirichinstitute.com/about">Jim Weirich&lt;/a>&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> showing off &lt;a href="https://github.com/rspec-given/rspec-given">rspec-given&lt;/a> at a conference a few years ago, and wondered if that would solve my problem here of wanting to have runtime warn me when my methods are misspelled or missing, without having_to_underscore_them.&lt;/p>
&lt;p>Now rspec-given would let me do that, but I&amp;rsquo;d have to switch from calling them all in turn inside a scenario block to calling them inside context blocks and passing blocks to each of the &lt;code>Given&lt;/code>, &lt;code>When&lt;/code>, etc methods. I think it would be something like (warning, untested)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="no">Rspec&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">feature&lt;/span> &lt;span class="s2">&amp;#34;Admin: Posts&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Given&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="vi">@user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="ss">:user&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:admin&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Given&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">login_as&lt;/span> &lt;span class="vi">@user&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">context&lt;/span> &lt;span class="s2">&amp;#34;authoring a post&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">When&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">visit&lt;/span> &lt;span class="n">new_admin_post_path&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">When&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">fill_in&lt;/span> &lt;span class="p">:&lt;/span>&lt;span class="err">…&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Then&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">visit&lt;/span> &lt;span class="n">root_url&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">And&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">expect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to&lt;/span> &lt;span class="n">have_content&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;RSpec feature specs&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now this didn&amp;rsquo;t &lt;em>quite&lt;/em> fit with what I wanted. However, I did wonder if it was possible to go down the route of having a &lt;code>Given&lt;/code> method that takes a token to identify the code it should call. (A method if you will.) It&amp;rsquo;s possible in ruby to call a method starting with a Capital letter, but convention dictates those are usually class/module names (constants) rather than methods.&lt;/p>
&lt;p>A little bit of hacking later and this is what I ended up getting working:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="no">RSpec&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">feature&lt;/span> &lt;span class="s2">&amp;#34;Admin: Posts&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scenario&lt;/span> &lt;span class="s2">&amp;#34;Authoring a post&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Given&lt;/span> &lt;span class="ss">:&amp;#34;I am logged in as an admin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">When&lt;/span> &lt;span class="ss">:&amp;#34;I publish a new post&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Then&lt;/span> &lt;span class="ss">:&amp;#34;I see the post on the homepage&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kp">protected&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">def_Given&lt;/span> &lt;span class="ss">:&amp;#34;I am logged in as an admin&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="ss">:user&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:admin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">login_as&lt;/span> &lt;span class="vi">@user&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">def_When&lt;/span> &lt;span class="ss">:&amp;#34;I publish a new post&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">visit&lt;/span> &lt;span class="n">new_admin_post_path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fill_in&lt;/span> &lt;span class="s2">&amp;#34;Title&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">with&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;RSpec feature specs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fill_in&lt;/span> &lt;span class="s2">&amp;#34;Body&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">with&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Some piffle about feature specs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click_on&lt;/span> &lt;span class="s2">&amp;#34;Publish!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">def_Then&lt;/span> &lt;span class="ss">:&amp;#34;I see the post on the homepage&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">visit&lt;/span> &lt;span class="n">root_url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">expect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to&lt;/span> &lt;span class="n">have_content&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;RSpec feature specs&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now there&amp;rsquo;s two extra things that makes this easier for me to write than underscored methods. Ruby doesn&amp;rsquo;t only allow &lt;code>:foo&lt;/code> as a symbol, it also allows &lt;code>:&amp;quot;foo bar&amp;quot;&lt;/code> for writing a symbol. You can then define a method based on that even though it has spaces in the method name.&lt;/p>
&lt;p>My text editor&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> also autocompletes ruby symbols from partial matches, which makes it easy to write out what I want in the scenario, run the spec and find out what methods need defining, then define the methods using autocomplete to save copy/pasting everything.&lt;/p>
&lt;p>By using actual methods for these, we get a couple of other happy accidents along the way. Most ruby installs now include &lt;a href="https://github.com/ruby/did_you_mean">did_you_mean&lt;/a> out the box, which suggests methods like the one you called if your method results in a &lt;code>NoMethodError&lt;/code>. This works quite nicely, you end up with something like&lt;/p>
&lt;pre tabindex="0">&lt;code>undefined method `When I pblish a new post&amp;#39; for #&amp;lt;RSpec::ExampleGroups::AdminPosts:0x00007faf1f9fc4c0&amp;gt;
Did you mean? When I publish a new post
&lt;/code>&lt;/pre>&lt;p>And then if you just run it without implementing any of the helper methods at all, you get a nice &lt;code>NoMethodError&lt;/code> telling you exactly what you need to implement:&lt;/p>
&lt;pre tabindex="0">&lt;code>NoMethodError:
undefined method `Given I am logged in as an admin&amp;#39; for #&amp;lt;RSpec::ExampleGroups::AdminPosts:0x00007fbd06598498&amp;gt;
&lt;/code>&lt;/pre>&lt;p>The magic behind that makes all this work is in &lt;a href="https://gist.github.com/caius/606b80252b176e353fe0893f8888dbbf">&lt;code>spec/support/given_when_then.rb&lt;/code>&lt;/a>, which is not terrible, but also probably not a great idea. 🙃&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>😿&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://macromates.com">TextMate 2&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>curl --resolve</title><link>https://caiustheory.com/curl--resolve/</link><pubDate>Sat, 14 Sep 2019 18:10:00 +0100</pubDate><guid>https://caiustheory.com/curl--resolve/</guid><description>&lt;p>Sometimes it&amp;rsquo;s useful to be able to craft a request to one server, using a DNS name that&amp;rsquo;s either not defined or currently pointed to a different IP. (Migrating webservers, testing a new webserver config out, etc.)&lt;/p>
&lt;p>Historically for HTTP calls this was easy, just set the &lt;code>Host&lt;/code> header as you make the http request to the IP directly:&lt;/p>
&lt;pre>&lt;code> curl -H &amp;quot;Host: caiustheory.com&amp;quot; http://10.200.0.1/
&lt;/code>&lt;/pre>
&lt;p>However, HTTPS throws a bit of a spanner in the works, if we just try to connect using an overridden &lt;code>Host&lt;/code> header, we get an error back from the server if it&amp;rsquo;s not configured with a certificate for the IP address:&lt;/p>
&lt;pre>&lt;code> $ curl -H &amp;quot;Host: caiustheory.com&amp;quot; https://10.200.0.1/
curl: (51) SSL: no alternative certificate subject name matches target host name '10.200.0.1'
&lt;/code>&lt;/pre>
&lt;p>Usually at this point I&amp;rsquo;d just start editing &lt;code>/etc/hosts&lt;/code> to add &lt;code>10.200.0.1 caius.name&lt;/code> to it and carry on testing. This is a pain when you&amp;rsquo;re testing more than one server, or you&amp;rsquo;re on a machine where you don&amp;rsquo;t have root access to edit &lt;code>/etc/hosts&lt;/code>.&lt;/p>
&lt;p>In later versions of curl there&amp;rsquo;s a solution for this built into the binary, in the form of the &lt;code>--resolve&lt;/code> flag. You can tell it to override the DNS lookup for a specific hostname/port combination. This in turn means that the correct host is forwarded to the server for the correct SSL certificate to be chosen to serve the request based on host.&lt;/p>
&lt;p>It takes the form &lt;code>--resolve HOST:PORT:IP&lt;/code> where &lt;code>HOST&lt;/code> is the human-friendly host, &lt;code>PORT&lt;/code> is the webserver&amp;rsquo;s port (convention is 80 for HTTP, 443 for HTTPS) and IP being the destination IP you want to hit. (As opposed to the one in DNS currently.)&lt;/p>
&lt;pre tabindex="0">&lt;code>$ curl --silent --head --resolve caiustheory.com:443:10.200.0.1 https://caiustheory.com | head -n1
HTTP/2 200
&lt;/code>&lt;/pre>&lt;p>And voila, you don&amp;rsquo;t need to fiddle with editing &lt;code>/etc/hosts&lt;/code>. Just use &lt;code>--resolve&lt;/code> to hit a different IP for a given host.&lt;/p></description></item><item><title>Cheaper Oil for Mini One R50</title><link>https://caiustheory.com/cheaper-oil-for-mini-one-r50/</link><pubDate>Tue, 02 Apr 2019 12:00:00 +0000</pubDate><guid>https://caiustheory.com/cheaper-oil-for-mini-one-r50/</guid><description>&lt;p>My Mini One 2003 R50 1.6 litre petrol engine takes specific BMW 5w30 Longlife-04 oil. (I believe the R52 and R53 models take the same oil too.) The oil is 5w30 fully synthetic made to BMW&amp;rsquo;s exacting standards.&lt;/p>
&lt;p>The cheapest I&amp;rsquo;ve found to buy currently is a GM (Vauxhall/Opel) manufactured one, made to BMW&amp;rsquo;s specifications. Searching for something like &amp;ldquo;dexos 2 5w30 gm&amp;rdquo; &lt;a href="https://www.ebay.co.uk/sch/i.html?_nkw=dexos+2+5w30+gm">on ebay&lt;/a> finds them at about £20 for 5 litres with free delivery in UK. (Comparatively, an equivalent from Castrol is about £50 at time of writing.)&lt;/p>
&lt;p>Sounds like a small saving, but if your Mini is anything like mine it needs topping up once a month or so, and I do a full oil/filter change every 5k miles as an attempt at longevity. Soon adds up.&lt;/p></description></item><item><title>Download All Your Gists</title><link>https://caiustheory.com/download-all-your-gists/</link><pubDate>Sun, 17 Mar 2019 14:32:30 +0000</pubDate><guid>https://caiustheory.com/download-all-your-gists/</guid><description>&lt;p>Over time I&amp;rsquo;ve managed to build up quite the collection of &lt;a href="https://gist.github.com/">Gists&lt;/a> over at Github, including secret ones there&amp;rsquo;s about 1200 currently. Some of these have useful code in, some are just garbage output. I&amp;rsquo;d quite like a local copy either way, so I can easily search&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> across them.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Install the &lt;code>gist&lt;/code> command from Github&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">brew install gist
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Login to your Github Account through the gist tool (it&amp;rsquo;ll prompt for your login credentials, then generate you an API Token to allow it future access.)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">gist --login
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Create a folder, go inside it and download all your gists!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">mkdir gist_archive
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> gist_archive
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> repo in &lt;span class="k">$(&lt;/span>gist -l &lt;span class="p">|&lt;/span> awk &lt;span class="s1">&amp;#39;{ print $1 }&amp;#39;&lt;/span>&lt;span class="k">)&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">do&lt;/span> git clone &lt;span class="nv">$repo&lt;/span> 2&amp;gt; /dev/null&lt;span class="p">;&lt;/span> &lt;span class="k">done&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Now you have a snapshot of all your gists. To update them in future, you can run the above for any new gists, and update all the existing ones with:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> gist_archive
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> i in */&lt;span class="p">;&lt;/span> &lt;span class="k">do&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="nb">cd&lt;/span> &lt;span class="nv">$i&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> git pull --rebase&lt;span class="o">)&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">done&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Now go forth and search out your favourite snippet you saved years ago and forgot about!&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;a href="https://beyondgrep.com">ack&lt;/a>, &lt;a href="https://geoff.greer.fm/ag/">ag&lt;/a>, &lt;a href="https://www.freebsd.org/cgi/man.cgi?query=grep&amp;amp;sektion=&amp;amp;n=1">grep&lt;/a>, &lt;a href="https://github.com/BurntSushi/ripgrep">ripgrep&lt;/a>, etc. Pick your flavour.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Prefixing Git Branch With Initials</title><link>https://caiustheory.com/prefixing-git-branch-with-initials/</link><pubDate>Wed, 21 Nov 2018 20:30:40 +0000</pubDate><guid>https://caiustheory.com/prefixing-git-branch-with-initials/</guid><description>&lt;p>Working somewhere where we prefix our branches with the creator&amp;rsquo;s initials, I sometimes forget to do so.&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> This leads to me having to rename the branch, typing out the whole name again after adding &lt;code>cd/&lt;/code> to the start of it.&lt;/p>
&lt;p>Computers are meant to solve repetitive problems for us, so let&amp;rsquo;s put it to work in this case too. My &lt;a href="https://github.com/caius/BinFiles">~/bin&lt;/a> contains &lt;a href="https://github.com/caius/BinFiles/blob/c7c5c6ababd70e65fa4d072bf8392aaa014c607c/git-current-branch">&lt;code>git current-branch&lt;/code>&lt;/a>, which returns the current branch name.&lt;/p>
&lt;p>If we hardcode the initials, this becomes a simple command to recall from our history:&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git branch --move --force cd/&lt;span class="k">$(&lt;/span>git current-branch&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But computers are supposed to solve all repetitive work, including knowing who I am, right? Correct, my local user account knows my full name, so we can work out my initials from that. Lets lean on the &lt;code>id(1)&lt;/code> command to lookup the user&amp;rsquo;s details then strip it down to just the initials.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">id -F
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; &amp;#34;Caius Durling&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">id -F &lt;span class="p">|&lt;/span> sed -Ee &lt;span class="s1">&amp;#39;s/(^| )(.)[^ ]+/\2/g&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> tr &lt;span class="s1">&amp;#39;A-Z&amp;#39;&lt;/span> &lt;span class="s1">&amp;#39;a-z&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; cd&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bingo, we can wrap that into a subshell passed to the branch move command and we&amp;rsquo;re done in a one-liner.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git branch --move --force &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>id -F &lt;span class="p">|&lt;/span> sed -Ee &lt;span class="s1">&amp;#39;s/(^| )(.)[^ ]+/\2/g&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> tr &lt;span class="s1">&amp;#39;A-Z&amp;#39;&lt;/span> &lt;span class="s1">&amp;#39;a-z&amp;#39;&lt;/span>&lt;span class="k">)&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="k">$(&lt;/span>git current-branch&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>I don&amp;rsquo;t follow that policy for my personal repos, or working on forks of other people&amp;rsquo;s code. And I&amp;rsquo;m human, so I forget.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>You can also replace &lt;code>--move --force&lt;/code> with &lt;code>-M&lt;/code>: &lt;code>git branch -M newname&lt;/code>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>On macOS you can use &lt;code>id -F&lt;/code> to return the full name of the user. Doing this on other platforms is left as an exercise for the reader.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>Yes, this is an incredibly naive way to initialize a name, but it&amp;rsquo;s good enough for the people I work with. Handling edge cases is left as … you got it, an exercise for the reader.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Struct-uring your data</title><link>https://caiustheory.com/struct-uring-your-data/</link><pubDate>Fri, 09 Nov 2018 00:31:00 +0000</pubDate><guid>https://caiustheory.com/struct-uring-your-data/</guid><description>&lt;p>In Ruby it&amp;rsquo;s easy to structure data in hashes and pass it around, and usually that leads to errors with calling methods on &lt;code>nil&lt;/code>, or misspelling the name of a key, or some such silly bug that we might catch earlier given a defined object with a custom Class behind it. But it&amp;rsquo;s so much work to create a Class just to represent some grab bag of data we&amp;rsquo;ve been handed, right? Well, maybe!&lt;/p>
&lt;p>Lets say we have some event data that we&amp;rsquo;re being sent and we want to do some stuff with it in memory, we could just represent this as an array of hashes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">events&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Writing&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">duration&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">15&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">started&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kp">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">finished&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kp">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Evening walk&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">duration&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">started&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kp">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">finished&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kp">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is not a &lt;em>bad&lt;/em> way to represent the data, but if we want to start asking questions of it like &amp;ldquo;find all events currently happening&amp;rdquo; it becomes trickier. We could filter the collection to just those &amp;ldquo;in progress&amp;rdquo; events with the following&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">events&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">select&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="o">|&lt;/span>&lt;span class="n">event&lt;/span>&lt;span class="o">|&lt;/span> &lt;span class="n">event&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:started&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="n">event&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:finished&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Next time someone reads this though, they have to figure out what it means to have an event that&amp;rsquo;s started but not finished. Also what happens when someone in future misremembers &lt;code>:finished&lt;/code> as &lt;code>:completed&lt;/code> when running over the data in new code?&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> Wouldn&amp;rsquo;t it be better if we could do the following instead?&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">events&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">select&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="o">|&lt;/span>&lt;span class="n">event&lt;/span>&lt;span class="o">|&lt;/span> &lt;span class="n">event&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">in_progress?&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>An easy way to do this is to just create a Struct for the event, with the extra method defined internally. Whilst we&amp;rsquo;re in there, we could add a couple more methods to make us querying the state of boolean attributes nicer to read(eh?)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="no">Event&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Struct&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="ss">:name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:duration&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:started&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:finished&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alias_method&lt;/span> &lt;span class="ss">:started?&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:started&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alias_method&lt;/span> &lt;span class="ss">:finished?&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:finished&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">in_progress?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">started?&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="n">finished?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then to create the objects, we can either use the positional arguments to &lt;code>.new&lt;/code> (same order as the symbols given to &lt;code>Struct.new&lt;/code>), or tap the object and use the setters directly for each attribute.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">events&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Event&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Writing&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">15&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kp">true&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kp">false&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Event&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tap&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="o">|&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Evening Walk&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">duration&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">60&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">started&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kp">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">finished&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kp">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; [#&amp;lt;struct Event&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># name=&amp;#34;Writing&amp;#34;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># duration=15,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># started=true,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># finished=false&amp;gt;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># #&amp;lt;struct Event&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># name=&amp;#34;Evening Walk&amp;#34;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># duration=60,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># started=true,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># finished=false&amp;gt;]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now we can use our easier-to-read code for selecting all in-progress events, or ignoring all of those. Or if we just want to grab all finished events, we now have a method to call—&lt;code>Event#finished?&lt;/code>—that conveys the intent of what it returns without having to look up the data structure of the hash to work out if that field is a &lt;code>String&lt;/code> or &lt;code>Boolean&lt;/code>.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;/p>
&lt;p>For super-powered structs, you don&amp;rsquo;t even need to assign them to a &lt;code>Constant&lt;/code>. You can just assign them to normal variables and use them locally in that scope without needing to define a constant.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Grabber&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">call&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Struct&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="ss">:success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:output&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alias_method&lt;/span> &lt;span class="ss">:success?&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:success&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">grab_data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kp">true&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kp">false&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kp">nil&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;ll handily return you an object you can interrogate for &lt;code>success?&lt;/code> and ask for the &lt;code>output&lt;/code> if it was successful. And no Constants were created in the making of this method. 🎉&lt;/p>
&lt;p>Keep an eye out for where you can Struct-ure your data. It might be more often than you expect.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>It would always returns &lt;code>true&lt;/code> - &lt;code>!nil&lt;/code>.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>That&amp;rsquo;s &lt;code>events.select(&amp;amp;:in_progress?)&lt;/code> for the golfers amongst you.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>&lt;code>…?&lt;/code> methods in ruby are truthy/falsy by convention.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Running rails tests under CircleCI 2.0 with MariaDB</title><link>https://caiustheory.com/running-rails-tests-under-circleci-2.0-with-mariadb/</link><pubDate>Wed, 11 Jul 2018 18:30:00 +0000</pubDate><guid>https://caiustheory.com/running-rails-tests-under-circleci-2.0-with-mariadb/</guid><description>&lt;p>&lt;a href="https://circleci.com">CircleCI&lt;/a> have released their version 2.0 platform, which is based on top of docker and moves the configuration for each project into a config file in the git repository.&lt;/p>
&lt;p>They have a bunch of documentation at &lt;a href="https://circleci.com/docs/2.0/">https://circleci.com/docs/2.0/&lt;/a>. Basic gist is the config file lives at &lt;code>.circleci/config.yml&lt;/code> and defines which images to run a series of commands in. You can either specify jobs to run in series, or a workflow containing jobs which can depend on each other and/or run in parallel.&lt;/p>
&lt;p>The first step is finding a base image that contains ruby, node and chrome/chromedriver so the the app runs, assets compile and rails feature specs work respectively.&lt;/p>
&lt;p>The available images for ruby are listed at &lt;a href="https://github.com/CircleCI-Public/circleci-dockerfiles/tree/master/ruby/images">https://github.com/CircleCI-Public/circleci-dockerfiles/tree/master/ruby/images&lt;/a>, and the mariadb images are listed at &lt;a href="https://github.com/CircleCI-Public/circleci-dockerfiles/tree/master/mariadb/images">https://github.com/CircleCI-Public/circleci-dockerfiles/tree/master/mariadb/images&lt;/a>. For the ruby images you&amp;rsquo;ll want to use the &lt;code>…-node-browsers&lt;/code> image as it has Node.js for assets and Chrome/chromedriver installed for headless browser testing.&lt;/p>
&lt;p>So the start of our config file looks something like the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">working_directory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;~/project&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">docker&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;circleci/ruby:2.4.1-node-browsers&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">RAILS_ENV&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;test&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;mariadb:10.2.12&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_DATABASE&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;app_test&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_USER&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;root&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_ALLOW_EMPTY_PASSWORD&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_HOST&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;localhost&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once we have that then we can start on setting up our rails environment to the point we can run tests. First of all we need to install all our ruby dependencies via &lt;a href="https://bundler.io">bundler&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Install ruby dependencies&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;bundle install --path vendor/bundle&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then we need to install our JS dependencies via &lt;a href="https://yarnpkg.com/lang/en/">yarn&lt;/a>, in much the same way as we did for the ruby dependencies.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Install js dependencies&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;yarn install&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then we need to sort out our database. There&amp;rsquo;s a chance that the docker instance for MariaDB hasn&amp;rsquo;t come up yet, so we can lean on a tool called &lt;code>dockerize&lt;/code> to wait for it to be available. Then we can ask rails to go ahead and setup our test database.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Wait for database to be available&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;dockerize -wait tcp://127.0.0.1:3306 -timeout 1m&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Setup database&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;bundle exec rake db:setup&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then finally we can run our tests as the final step.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Run tests&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;bundle exec rspec&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Putting it all together, we have the following in &lt;code>.circleci/config.yml&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">working_directory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;~/project&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">docker&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;circleci/ruby:2.4.1-node-browsers&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">RAILS_ENV&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;test&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;mariadb:10.2.12&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_DATABASE&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;app_test&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_USER&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;root&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_ALLOW_EMPTY_PASSWORD&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MYSQL_HOST&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;localhost&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Install ruby dependencies&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;bundle install --path vendor/bundle&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Install js dependencies&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;yarn install&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Wait for database to be available&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;dockerize -wait tcp://127.0.0.1:3306 -timeout 1m&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Setup database&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;bundle exec rake db:setup&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Run tests&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;bundle exec rspec&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>May your test runs always be green and your bugs be squished.&lt;/p></description></item><item><title>Overcommit git hooks: puppet validate</title><link>https://caiustheory.com/overcommit-git-hooks-puppet-validate/</link><pubDate>Thu, 05 Jul 2018 14:44:41 +0000</pubDate><guid>https://caiustheory.com/overcommit-git-hooks-puppet-validate/</guid><description>&lt;p>Computers are great at automatically checking things, and git has a mechanism for running hooks before events happen. Bosh these two things together and you can have git trigger anything you like before you&amp;rsquo;re allowed to commit, which in turn means you can sanity check exactly what you&amp;rsquo;re committing to make sure it meets whatever criteria you have.&lt;/p>
&lt;p>To make it easy to manage my git hooks in a consistent fashion, I use a tool called &lt;a href="https://github.com/brigade/overcommit">overcommit&lt;/a>. This comes with a config file to tell it what you want triggered when, and a bunch of standard plugins to choose from.&lt;/p>
&lt;p>In a &lt;a href="https://puppet.com">puppet&lt;/a> repo for instance, I have it check&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://bundler.io">bundler&lt;/a> is happy everything&amp;rsquo;s installed&lt;/li>
&lt;li>&lt;a href="http://puppet-lint.com">puppet-lint&lt;/a> is happy with any changed puppet files&lt;/li>
&lt;li>Any JSON or YAML files involved in the commit have valid syntax&lt;/li>
&lt;li>Any shell scripts are valid (according to &lt;a href="https://www.shellcheck.net">shellcheck&lt;/a>)&lt;/li>
&lt;li>There is no trailing whitespace left in files&lt;/li>
&lt;/ul>
&lt;p>This usually means something like the following in &lt;code>.overcommit.yml&lt;/code> in the git repo&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">PreCommit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">BundleCheck&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">JsonSyntax&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">PuppetLint&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ShellCheck&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">YamlSyntax&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">on_warn&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">fail&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For the most part this works absolutely great. I have on occasion noticed that &lt;a href="http://puppet-lint.com">puppet-lint&lt;/a> will let invalid puppet syntax slip through though which is irritating to find after you&amp;rsquo;ve pushed the changes up to the puppetmaster. The &lt;a href="https://puppet.com">puppet&lt;/a> command line tool has a validate subcommand however, so we can hook that into overcommit as a custom hook in the repo.&lt;/p>
&lt;p>To do this we need to add our custom hook into the right directory, and we&amp;rsquo;re adding a hook to run before commits, so it goes into &lt;code>.git-hooks/pre_commit&lt;/code>. Lets name it for what it does, validating puppet syntax. So into &lt;code>puppet_validate.rb&lt;/code> we put the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># .git-hooks/pre_commit/puppet_validate.rb&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">module&lt;/span> &lt;span class="nn">Overcommit::Hook::PreCommit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">class&lt;/span> &lt;span class="nc">PuppetValidate&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="no">Base&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">run&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">errors&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sx">%w(puppet parser validate)&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:args&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="n">applicable_files&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="ss">:pass&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">success?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">[&lt;/span>&lt;span class="ss">:fail&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then we need to tell &lt;a href="https://github.com/brigade/overcommit">overcommit&lt;/a> that it needs to run this custom hook as a check whenever we commit, that goes into &lt;code>.overcommit.yml&lt;/code> under the &lt;code>PreCommit&lt;/code> key:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">PreCommit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">PuppetValidate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;Validates puppet syntax&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">include&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;**/*.pp&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hey voila, along with all our other safety checks we&amp;rsquo;re now checking that any puppet files added or changed in the repo have valid syntax.&lt;/p></description></item><item><title>Cleaning up locally installed Rubies &amp; Gems</title><link>https://caiustheory.com/cleaning-up-locally-installed-rubies-gems/</link><pubDate>Sun, 12 Nov 2017 11:30:24 +0000</pubDate><guid>https://caiustheory.com/cleaning-up-locally-installed-rubies-gems/</guid><description>&lt;p>Given the following is broadly true:&lt;/p>
&lt;ul>
&lt;li>Rubies installed to &lt;code>~/.rubies&lt;/code> (via ruby-install most likely)&lt;/li>
&lt;li>Gems for each ruby version installed under ~/.gem (via chruby most likely)&lt;/li>
&lt;/ul>
&lt;p>What to do when you want to reclaim some disk space? Delete unused ruby versions of course! Pretty straight forward, look in ~/.rubies for ones you want to remove, then delete them.&lt;/p>
&lt;pre>&lt;code>$ ls ~/.rubies
ruby-2.0.0
ruby-2.1.7
ruby-2.3.1
ruby-2.4.1
$ rm -r ~/.rubies/ruby-{2.0.0,2.1.7}
&lt;/code>&lt;/pre>
&lt;p>Then the problem is we&amp;rsquo;re left with artifacts hanging around, namely any gems we installed for ruby 2.0.0 or 2.1.7 are still present under &lt;code>~/.gem&lt;/code> using up disk space. We could go through and find them by hand, or we could get the computer to delete anything under &lt;code>~/.gem&lt;/code> that doesn&amp;rsquo;t have a corresponding runtime under &lt;code>~/.rubies&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">diff --old-line-format&lt;span class="o">=&lt;/span> --unchanged-line-format&lt;span class="o">=&lt;/span> --new-line-format&lt;span class="o">=&lt;/span>&lt;span class="nv">$HOME&lt;/span>/.gem/ruby/%L &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &amp;lt;&lt;span class="o">(&lt;/span>ls ~/.rubies &lt;span class="p">|&lt;/span> sed -Ee &lt;span class="s1">&amp;#39;s/ruby-|-p[0-9]+//g&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &amp;lt;&lt;span class="o">(&lt;/span>ls ~/.gem/ruby&lt;span class="o">)&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="p">|&lt;/span> xargs -pL1 rm -r
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(&lt;code>xargs -pL1&lt;/code> will prompt with each command it wants to run before running it - answer &lt;code>y&lt;/code> to proceed, anything else to prevent it running that command. Lets you see what ruby versions it is removing before it does so.)&lt;/p>
&lt;pre>&lt;code>$ ls ~/.gem/ruby
2.0.0
2.1.7
2.3.1
2.4.1
$ diff --old-line-format= --unchanged-line-format= --new-line-format=$HOME/.gem/ruby/%L \
&amp;lt;(ls ~/.rubies | sed -Ee 's/ruby-|-p[0-9]+//g') &amp;lt;(ls ~/.gem/ruby) \
| xargs -pL1 rm -r
rm -r /Users/caius/.gem/ruby/2.0.0?...y
rm -r /Users/caius/.gem/ruby/2.1.7?...y
$ ls ~/.gem/ruby
2.3.1
2.4.1
&lt;/code>&lt;/pre>
&lt;p>And now revel in your reclaimed disk space. (Hunting other large folders/items on your disk? &lt;a href="http://dev.yorhel.nl/ncdu">&lt;code>ncdu&lt;/code>&lt;/a> is a great tool for that.)&lt;/p></description></item><item><title>Something Goes Here</title><link>https://caiustheory.com/something-goes-here/</link><pubDate>Fri, 10 Nov 2017 00:27:07 +0000</pubDate><guid>https://caiustheory.com/something-goes-here/</guid><description>&lt;!-- raw HTML omitted -->
&lt;pre>&lt;code>Something goes here
and something else
over there slowly
wrapping lines a
little each time
oh no, you fucked
up one little comma
and now everything is running away drastically from you
End it.
&lt;/code>&lt;/pre>
&lt;!-- raw HTML omitted --></description></item><item><title>git git git git git</title><link>https://caiustheory.com/git-git-git-git-git/</link><pubDate>Tue, 26 Sep 2017 11:00:23 +0000</pubDate><guid>https://caiustheory.com/git-git-git-git-git/</guid><description>&lt;p>Ever found you&amp;rsquo;ve accidentally entered too many &lt;code>git&lt;/code>s in your terminal and wondered if there&amp;rsquo;s a solution to it? I quite often type &lt;code>git&lt;/code> then go away and come back, then type a full &lt;code>git status&lt;/code> after it. This leads to a lovely (annoying) error out the box:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ git git status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git: &lt;span class="s1">&amp;#39;git&amp;#39;&lt;/span> is not a git command. See &lt;span class="s1">&amp;#39;git --help&amp;#39;&lt;/span>.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What a git.&lt;/p>
&lt;p>My initial thought was overriding the &lt;code>git&lt;/code> binary in my &lt;code>$PATH&lt;/code> and having it strip any leading arguments that match &lt;code>git&lt;/code>, so we end up running just the &lt;code>git status&lt;/code> at the end of the arguments. An easier way is to just use &lt;a href="https://git-scm.com/docs/git-config">&lt;code>git-config&lt;/code>&lt;/a>&amp;rsquo;s &lt;code>alias.*&lt;/code> functionality to expand the first argument being &lt;code>git&lt;/code> to a shell command.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git config --global alias.git &lt;span class="s1">&amp;#39;!exec git&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Which adds the following git config to your &lt;code>.gitconfig&lt;/code> file&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="k">[alias]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">git&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">!exec git&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then you&amp;rsquo;ll find you can &lt;code>git git&lt;/code> to your heart&amp;rsquo;s content&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ git sha
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cc9c642663c0b63fba3964297c13ce9b61209313
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git git sha
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cc9c642663c0b63fba3964297c13ce9b61209313
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git git git git git git git git git git git git git git git git git git git git git git git git git git sha
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cc9c642663c0b63fba3964297c13ce9b61209313
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(&lt;code>git sha&lt;/code> is an alias for &lt;code>git rev-parse HEAD&lt;/code>.)&lt;/p>
&lt;p>See what other git alias&amp;rsquo; I have in my &lt;a href="https://github.com/caius/zshrc/blob/master/dotfiles/gitconfig">&lt;code>~/.gitconfig&lt;/code>&lt;/a>, and laugh at all the typo corrections I have in there. (Yes, git provides autocorrection if you enable it, but I&amp;rsquo;m used to these typos working!)&lt;/p>
&lt;p>Now &lt;code>git&lt;/code> back to doing useful things!&lt;/p></description></item><item><title>Upgrading Microserver G8 CPU</title><link>https://caiustheory.com/upgrading-microserver-g8-cpu/</link><pubDate>Wed, 09 Aug 2017 00:30:23 +0000</pubDate><guid>https://caiustheory.com/upgrading-microserver-g8-cpu/</guid><description>&lt;p>My home server is a &lt;a href="https://www.hpe.com/uk/en/product-catalog/servers/proliant-servers/pip.hpe-proliant-microserver-gen8.5379860.html">HP Proliant Microserver Gen 8&lt;/a>, which is modestly powerful and runs everything I need at home in a fairly compact footprint without being too noisy or power hungry.&lt;/p>
&lt;p>Both the G8 and the previous revision, the G7, are moderately expandable in terms of memory &amp;amp; storage devices. (Not least of which is an internal USB port, which is useful plugging the SmartOS boot device into, no chance of it being knocked out!) I&amp;rsquo;ve upgraded the memory and HDDs in the time I&amp;rsquo;ve had the machine. (&lt;a href="/finding-cheap-microserver-g8-memory/">Here&amp;rsquo;s how I upgraded the memory on the cheap&lt;/a>!)&lt;/p>
&lt;p>The Gen 8 specifically is a little more upgradable however, as it comes with a 1155 CPU socket. Mine contained a &lt;a href="https://ark.intel.com/products/71074/Intel-Celeron-Processor-G1610T-2M-Cache-2_30-GHz">Celeron G1610T CPU&lt;/a> from new, which whilst quicker than the AMD one in the G7, was only two cores / two threads and not massively fast in the grand scheme of things.&lt;/p>
&lt;p>Given I run a few different things on the home server, it acts as a NAS for a handful of laptops, &lt;a href="https://www.plex.tv/">plex server&lt;/a>, &lt;a href="https://www.crashplan.com/">crashplan&lt;/a> backup server, gathers various stats from network devices &amp;amp; runs the &lt;a href="https://unifi-hd.ubnt.com">unifi controller&lt;/a>. Mostly it&amp;rsquo;s fine, but transcoding in Plex specifically burns the CPU and on the odd occasion I&amp;rsquo;ve noticed it being slower than realtime and having to wait for the server to catch up.&lt;/p>
&lt;p>So what to do? As you&amp;rsquo;ve no doubt guessed from the title of the post, I upgraded the CPU in it. I did some research and found &lt;a href="https://b3n.org/installed-xeon-e3-1230v2-in-gen8-hp-microserver/">someone else who documented the upgrading process&lt;/a>, as well as the &lt;a href="http://n40l.wikia.com/wiki/Cpu_gen8">N40L wiki listing potential upgrade candidates&lt;/a>. I then pulled together my own table of processors, specs &amp;amp; price on fleabay to work out which I want.&lt;/p>
&lt;p>My criteria were more than 2 cores/threads, ECC ram &lt;strong>has&lt;/strong> to be supported and ideally not much higher TDP than the stock CPU. &lt;a href="https://support.plex.tv/hc/en-us/articles/201774043">Plex guidelines for CPU power&lt;/a> state that as a (very) rough guideline, you need a 2000 PassMark score per 1080p transcode. Given I would like other things running alongside Plex, allowing 2-3x that figure sounds ideal.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>CPU&lt;/th>
&lt;th>Cores&lt;/th>
&lt;th>Threads&lt;/th>
&lt;th>TDP (W)&lt;/th>
&lt;th>Passmark&lt;/th>
&lt;th>Price (£)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;em>G1610T&lt;/em>&lt;/td>
&lt;td>2&lt;/td>
&lt;td>2&lt;/td>
&lt;td>35&lt;/td>
&lt;td>2322&lt;/td>
&lt;td>12.00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>E3-1220L v2&lt;/td>
&lt;td>2&lt;/td>
&lt;td>4&lt;/td>
&lt;td>17&lt;/td>
&lt;td>3701&lt;/td>
&lt;td>120.00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>E3-1220L&lt;/td>
&lt;td>2&lt;/td>
&lt;td>4&lt;/td>
&lt;td>20&lt;/td>
&lt;td>3563&lt;/td>
&lt;td>60.00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>E3-1260L&lt;/td>
&lt;td>4&lt;/td>
&lt;td>8&lt;/td>
&lt;td>45&lt;/td>
&lt;td>6534&lt;/td>
&lt;td>80.00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>E3-1265L&lt;/td>
&lt;td>4&lt;/td>
&lt;td>8&lt;/td>
&lt;td>45&lt;/td>
&lt;td>6054&lt;/td>
&lt;td>64.00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>E3-1265L v2&lt;/strong>&lt;/td>
&lt;td>4&lt;/td>
&lt;td>8&lt;/td>
&lt;td>45&lt;/td>
&lt;td>7733&lt;/td>
&lt;td>133.00&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;em>Stock CPU is first in the list for comparison. Bold one is the chosen upgrade.&lt;/em>&lt;/p>
&lt;p>After some deliberation, I decided to pick up the E3-1265L v2 from Ebay. It has a slightly higher TDP, but not so much that I&amp;rsquo;m worried about the temperature in the server. Most importantly it supports ECC ram &amp;amp; quadruples the physical cores, whilst providing a whopping eight threads for processing power. More than enough for a couple of concurrent Plex transcodes with cycles left over for other things at the same time.&lt;/p>
&lt;p>I ordered it from a Hong Kong seller, and it arrived in the UK after 10 days or so as expected. It came with thermal paste, which I applied in a cross formation before refitting everything. The G8 is really easy to pull apart, HP really thought about that!&lt;/p>
&lt;p>First boot with the processor went very smoothly, SmartOS recognises it quite happily.&lt;/p>
&lt;pre>&lt;code> [root@oscar ~]# sysinfo | grep -i cpu
&amp;quot;CPU Type&amp;quot;: &amp;quot;Intel(R) Xeon(R) CPU E3-1265L V2 @ 2.50GHz&amp;quot;,
&amp;quot;CPU Virtualization&amp;quot;: &amp;quot;vmx&amp;quot;,
&amp;quot;CPU Physical Cores&amp;quot;: 1,
&amp;quot;CPU Total Cores&amp;quot;: 8,
&lt;/code>&lt;/pre>
&lt;p>I&amp;rsquo;m also happy with the temperatures, even after streaming a couple of videos via plex for an hour or so, whilst backing up a laptop via crashplan, as well as the usual stuff that&amp;rsquo;s always running on the machine, everything was still well within normal ranges.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Sensor&lt;/th>
&lt;th>Value&lt;/th>
&lt;th>Units&lt;/th>
&lt;th>State&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Inlet Ambient&lt;/td>
&lt;td>22.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CPU&lt;/td>
&lt;td>40.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>P1 DIMM 1-2&lt;/td>
&lt;td>40.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Chipset&lt;/td>
&lt;td>56.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Chipset Zone&lt;/td>
&lt;td>44.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>VR P1 Zone&lt;/td>
&lt;td>61.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>iLO Zone&lt;/td>
&lt;td>49.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>PCI 1 Zone&lt;/td>
&lt;td>40.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Sys Exhaust&lt;/td>
&lt;td>48.000&lt;/td>
&lt;td>degrees C&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Fan 1&lt;/td>
&lt;td>12.544&lt;/td>
&lt;td>percent&lt;/td>
&lt;td>ok&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>All in all, great success!&lt;/p>
&lt;p> 
 &lt;/p>
&lt;p>&lt;em>Updated 2018-12-30: &lt;a href="https://twitter.com/tomwardill/">@tomwardill&lt;/a> &lt;a href="https://twitter.com/tomwardill/status/999002779887824896">notes&lt;/a> the E3-1230L V3 doesn&amp;rsquo;t fit: &amp;ldquo;The E3-1230L V3 that you list doesn&amp;rsquo;t fit, it&amp;rsquo;s a 1150 socket, not a 1155&amp;rdquo;. The table of candidates has been altered to remove it.&lt;/em>&lt;/p></description></item><item><title>Wenlock Olympian Triathlon 2017</title><link>https://caiustheory.com/wenlock-olympian-triathlon-2017/</link><pubDate>Thu, 13 Jul 2017 12:55:45 +0000</pubDate><guid>https://caiustheory.com/wenlock-olympian-triathlon-2017/</guid><description>&lt;p>Second year in a row doing this Tri, &lt;a href="http://caiustheory.com/much-wenlock-triathlon-2016/">last year&lt;/a> I came away feeling like I hadn&amp;rsquo;t given it my best and wanted to return to complete unfinished business. &lt;em>(Spoilers: I managed better this year.)&lt;/em>&lt;/p>
&lt;p>&lt;strong>500m Swim: 00:10:37&lt;/strong> &lt;em>(&lt;a href="https://www.strava.com/activities/1076088498">Strava&lt;/a>)&lt;/em>&lt;/p>
&lt;p>Started last in a lane of three, didn&amp;rsquo;t get overtaken which meant swimming at my own pace without being under pressure was easily achieved. Failed to exit the pool initially, dropped a handful of seconds there for sure.&lt;/p>
&lt;p>Didn&amp;rsquo;t feel like I was pushing too hard, certainly felt energetic after leaving the building. Given my lack of swimming this year, I&amp;rsquo;m surprised at how well it went. Strength training over the winter months has definitely paid off more than I expected.&lt;/p>
&lt;p>Took nearly a minute off my previous swim time, which is more than I would&amp;rsquo;ve expected. Was only +7 seconds off my estimated time when entering too!&lt;/p>
&lt;p>&lt;strong>19km Cycle 00:45:44&lt;/strong> &lt;em>(&lt;a href="https://www.strava.com/activities/1076088548">Strava&lt;/a>)&lt;/em>&lt;/p>
&lt;p>The wonderful (👻) cycle route down and back up Wenlock Edge. Ran out of gear heading down the valley side (again), coasted most of the way down. Attempted to pace myself on the climbing, keeping an eye on my heart rate to know whether I could push harder or needed to ease off. Felt strong nearly all the way round, only came close to blowing on the final 15% climb (which was also nearer the end than I remembered/expected!)&lt;/p>
&lt;p>Got off the bike with less left in my legs than I thought whilst I was in the saddle. Took a solid 11 minutes 10 seconds off my previous time (which did include walking to be fair - none of that this year) which I&amp;rsquo;m &lt;em>very&lt;/em> happy with. Think I paced it nigh on perfectly on the day. Probably my strongest discipline currently too.&lt;/p>
&lt;p>&lt;strong>7km Run 00:53:06&lt;/strong> &lt;em>(&lt;a href="https://www.strava.com/activities/1076088534">Strava&lt;/a>)&lt;/em>&lt;/p>
&lt;p>Started the run feeling like crap. First couple of km is a mostly flat trail run, where I didn&amp;rsquo;t push very hard and was basically attempting to find some energy from somewhere. Pretty sure this was a mental battle rather than physical, no cramps or super tired muscles.&lt;/p>
&lt;p>A friend overtook me about 2.5km in and rather handily goaded me on by saying, &amp;ldquo;See you at the end!&amp;rdquo; as he went past (Thanks Paul!) which naturally made me kick harder and try to stick with him. Clung on to the halfway point (and the massive hill they make you climb just to turn round at the summit), and pulled ahead coming back down the route.&lt;/p>
&lt;p>Resorted to walking some sections of the run (probably about 750m in total), tailing and then dropping back from my mate in the last kilometre. (Dropped a minute in total to him on the run.) Technically I ran a 10k this season, but I&amp;rsquo;ve not run aside from that.&lt;/p>
&lt;p>(Also binned my trainers upon returning home. They&amp;rsquo;ve finally given up after being beaten on pavements &amp;amp; woodland floors for about 50 miles.)&lt;/p>
&lt;p>&lt;strong>Total 01:49:27&lt;/strong> &lt;em>(Previously 02:14:40)&lt;/em>&lt;/p>
&lt;p>Completed in under two hours! Completely astounded at that, especially as I don&amp;rsquo;t &lt;em>feel&lt;/em> like I&amp;rsquo;ve been training much this year. (I have, but more socially than on a strict timetable and without doing many previous events this season.)&lt;/p>
&lt;p>If you&amp;rsquo;d told me at the end of last year that my second attempt would take ~25 minutes off my finish time, I&amp;rsquo;d have laughed at you.&lt;/p>
&lt;p>&lt;a href="http://www.wenlock-olympian-society.org.uk/games/triathlon/">Wenlock Olympian Triathlon&lt;/a> is definitely my favourite Triathlon, and also the most challenging I&amp;rsquo;ve done to date. I&amp;rsquo;m intending on doing it next year and seriously aiming to take at least another 10 minutes off my total time.&lt;/p></description></item><item><title>Raspberry Pi 3 as an emergency router</title><link>https://caiustheory.com/raspberry-pi-3-as-an-emergency-router/</link><pubDate>Tue, 09 May 2017 20:55:00 +0000</pubDate><guid>https://caiustheory.com/raspberry-pi-3-as-an-emergency-router/</guid><description>&lt;p>Given a dead router, how do you get back online whilst you wait for the replacement part to arrive? Grab a Raspberry Pi 3 off the shelf, along with a USB to Ethernet adapter and hey presto the internet works again.&lt;/p>
&lt;p>This is with a fibre modem (FTTC), using PPPoE to connect out. Plug the modem (WAN) into the RPi&amp;rsquo;s ethernet port, and plug the LAN switch into the USB adapter.&lt;/p>
&lt;p>First thing is to get the WAN link working, get it talking PPPoE to the ISP. Usually this will be configured in &lt;code>/etc/ppp/pppoe.conf&lt;/code> (depends on your linux distro). (That&amp;rsquo;ll require your username/password for your ISP usually too.)&lt;/p>
&lt;p>Get it up &amp;amp; connected, and make sure you can ping the internet from the RPi. Then it&amp;rsquo;s time to get the LAN working. Give it a static IP in the range you want shared out.&lt;/p>
&lt;pre tabindex="0">&lt;code># /etc/network/interfaces
iface eth0 inet static
address 192.168.1.1
netmask 255.255.255.0
gateway 192.168.1.1
auto eth1
iface eth1 inet dhcp
&lt;/code>&lt;/pre>&lt;p>Get a dhcp server running on the LAN connection,&lt;/p>
&lt;pre tabindex="0">&lt;code># /etc/dhcpcd.conf
interface eth0
static ip_address=192.168.1.1
static routers=192.168.1.1
static domain_name_servers=8.8.8.8,8.8.4.4
&lt;/code>&lt;/pre>&lt;p>And then it&amp;rsquo;s time to handle WAN -&amp;gt; LAN traffic and the reverse. Make sure you have packet forwarding enabled, and then setup the firewall to handle NAT and also keep out undesirable traffic.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sysctl net.ipv4.ip_forward&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -F
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -X
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -t nat -F
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -t nat -X
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -i lo -j ACCEPT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -i eth0 -j ACCEPT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -f -j DROP
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">iptables -A INPUT -j DROP
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hey presto, you have a working emergency router. In testing I found my fibre connection (80/20Mb) was slower than the traffic the RPi could push, so didn&amp;rsquo;t notice any difference vs my normal router. (Although I did disable a bunch of automated stuff, so there was less contention on the WAN link.)&lt;/p></description></item><item><title>Finding cheap Microserver G8 memory</title><link>https://caiustheory.com/finding-cheap-microserver-g8-memory/</link><pubDate>Tue, 09 May 2017 19:03:00 +0000</pubDate><guid>https://caiustheory.com/finding-cheap-microserver-g8-memory/</guid><description>&lt;p>I&amp;rsquo;ve been wanting to drop more memory in my &lt;a href="https://www.hpe.com/uk/en/product-catalog/servers/proliant-servers/pip.hpe-proliant-microserver-gen8.5379860.html">HP Microserver G8&lt;/a>, but hoping to find a cheaper alternative to buying new sticks from &lt;a href="http://uk.crucial.com/gbr/en/">Crucial&lt;/a>. I needed one or two 4GB sticks, but they had to be ECC of course.&lt;/p>
&lt;p>At the time of writing (May 2017), &lt;a href="http://uk.crucial.com/gbr/en/compatible-upgrade-for/HP-Compaq/proliant-microserver-gen8">Crucial&amp;rsquo;s offering for the G8&lt;/a> shows a 4GB stick to be £43.19, and an 8GB stick to be £81.59. This was a little more than I wanted to pay, but I was struggling to find anything on eBay or Amazon UK that I could be sure was ECC, and also cheaper.&lt;/p>
&lt;p>Eventually I wondered what else had compatible memory, after all this isn&amp;rsquo;t a bespoke machine. It should share the same memory specifications as plenty of other machines. The spec I was looking for was:&lt;/p>
&lt;ul>
&lt;li>DDR3 240-Pin UDIMM&lt;/li>
&lt;li>ECC&lt;/li>
&lt;li>1600Mhz (or faster)&lt;/li>
&lt;li>4 or 8GB sticks&lt;/li>
&lt;/ul>
&lt;p>After a little while of searching, I happened to find the previous Mac Pro (ie. the tower, not the trashcan) also uses that specification of memory. One quick search on eBay and up turned someone selling off his 4GB sticks where he&amp;rsquo;d upgrade his Mac Pro to 8GB sticks across the board. £29 for 2x 4GB sticks is better than I was hoping for, and once fitted in the Microserver they work flawlessly.&lt;/p>
&lt;p>(The onboard management software warns me that some processor features are disabled because I&amp;rsquo;m not using HP Approved memory, but it also logged that warning when I &lt;em>was&lt;/em> using HP Approved memory previously and the machine worked perfectly then. No doubt it&amp;rsquo;s to make IT Managers who don&amp;rsquo;t like warnings spend more money with HP.)&lt;/p></description></item><item><title>Bash script setup</title><link>https://caiustheory.com/bash-script-setup/</link><pubDate>Tue, 09 May 2017 18:23:58 +0000</pubDate><guid>https://caiustheory.com/bash-script-setup/</guid><description>&lt;p>Recently I&amp;rsquo;ve been writing a bunch of bash scripts for various things. As some up-front safety checks I&amp;rsquo;ve taken to opening every script with the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/usr/bin/env bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[[&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$TRACE&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">]]&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">set&lt;/span> -o xtrace
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> -o errexit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> -o nounset
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> -o pipefail
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> -o noclobber
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Other things I&amp;rsquo;m also trying to be good about doing:&lt;/p>
&lt;ul>
&lt;li>using &lt;code>readonly&lt;/code> when declaring variables which shouldn&amp;rsquo;t be mutated&lt;/li>
&lt;li>Trapping errors using an error function, and cleaning up anything temporary in there&lt;/li>
&lt;/ul>
&lt;p>And some useful reading I ran across in my quest to level up bash-scripts:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://redsymbol.net/articles/bash-exit-traps/">Bash Exit Traps&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://redsymbol.net/articles/unofficial-bash-strict-mode/">Use the unofficial Bash Strict Mode&lt;/a> (Yes, &lt;em>two&lt;/em> posts from &lt;a href="http://redsymbol.net/">http://redsymbol.net/&lt;/a>. Well worth reading.)&lt;/li>
&lt;li>&lt;a href="https://jvns.ca/blog/2017/03/26/bash-quirks/">Bash scripting quirks &amp;amp; safety tips&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://wiki.bash-hackers.org/">Bash hackers wiki&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>BMW 328i crankshaft sensor issue</title><link>https://caiustheory.com/bmw-328i-crankshaft-sensor-issue/</link><pubDate>Fri, 21 Apr 2017 22:18:00 +0000</pubDate><guid>https://caiustheory.com/bmw-328i-crankshaft-sensor-issue/</guid><description>&lt;p>My 1996 e36 BMW 328i Convertible was having trouble starting, and it&amp;rsquo;s always broken up &lt;em>slightly&lt;/em> at idle since I took ownership of the car. On a couple of hot days last summer it also stalled during idle, then started doing it again recently (even though the ambient temperature was much colder.)&lt;/p>
&lt;p>The main sympton at the point I took notice was it struggling to start, then hunting at idle until warm, then promptly stalling when warm and idling. It would also cut out when coming to a stop at junctions.&lt;/p>
&lt;p>Reading the codes showed one related to the crankshaft sensor:&lt;/p>
&lt;blockquote>
&lt;p>53 Crankshaft Sensor&lt;/p>
&lt;/blockquote>
&lt;p>&lt;em>(Codes can also show up in hex, which would be &amp;ldquo;83 Crankshaft Sensor&amp;rdquo;.)&lt;/em>&lt;/p>
&lt;p>I duly replaced both the Crankshaft Sensor (Part # 12141703277) and the Camshaft Sensor (Part # 12141703221), but it was still throwing the crankshaft sensor code.&lt;/p>
&lt;p>Upon closer inspection, the sensor wire in the plug for the crankshaft sensor wasn&amp;rsquo;t pushed fully into the socket under the intake manifold. This lead to the ECU not being able to get a signal from the sensor, so it quite correctly threw a code and didn&amp;rsquo;t run correctly.&lt;/p>
&lt;p>Made sure all the pins were seated in the plug correctly, and reconnected the plug under the intake manifold and she started up perfectly. Drives much better, and the engine pulls more smoothly all the way up the rev range.&lt;/p></description></item><item><title>Stop HealthKit causing SIGABRT</title><link>https://caiustheory.com/stop-healthkit-causing-sigabrt/</link><pubDate>Sat, 15 Oct 2016 09:15:00 +0000</pubDate><guid>https://caiustheory.com/stop-healthkit-causing-sigabrt/</guid><description>&lt;p>You have some crazy idea for an iOS app that uses HealthKit so you fire up Xcode, create a new project &amp;amp; add the HealthKit entitlement. Follow the tutorial to request authorization from the &lt;code>HKHealthKitStore&lt;/code>. Hit run to make sure the app compiles and find that it instantly crashes with a &lt;code>SIGABRT&lt;/code> in &lt;code>AppDelegate&lt;/code>.&lt;/p>
&lt;p>Puzzled by this you go over the minimal amount of code you&amp;rsquo;ve added and pare it right down to just the &lt;code>HKHealthKitStore.requestAuthorization&lt;/code> call which is still causing the &lt;code>SIGABRT&lt;/code> as soon as the app tries to boot.&lt;/p>
&lt;p>The missing piece of the puzzle is &lt;code>Info.plist&lt;/code> needs a key adding to it for the HealthKit authorisation screen. The documentation helpfully forgets to mention this however. Here&amp;rsquo;s some quick simple steps to fix it:&lt;/p>
&lt;ol>
&lt;li>Open &lt;code>Info.plist&lt;/code> in Xcode&lt;/li>
&lt;li>Click the &lt;code>(+)&lt;/code> at the top to add a new key/value to the file&lt;/li>
&lt;li>Enter &amp;ldquo;Privacy - Health Share Usage Description&amp;rdquo; for the key&lt;/li>
&lt;li>Enter a useful message to the user explaining why they should allow access to their healthkit data for your app for the value&lt;/li>
&lt;li>Run your app and see the HealthKit authorisation sheet appear&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>NB&lt;/strong>: if you want to update/write any data to healthkit, you&amp;rsquo;ll need to add the &amp;ldquo;Privacy - Health Update Usage Description&amp;rdquo; key with a description as well.&lt;/p></description></item><item><title>Remove OS X Disk Password</title><link>https://caiustheory.com/remove-os-x-disk-password/</link><pubDate>Fri, 16 Sep 2016 10:27:00 +0000</pubDate><guid>https://caiustheory.com/remove-os-x-disk-password/</guid><description>&lt;p>I recently reinstalled a laptop and in doing so setup full disk encryption in a slightly strange fashion. The basic flow I followed was:&lt;/p>
&lt;ol>
&lt;li>Boot into Recovery mode (hold ⌘-R at boot)&lt;/li>
&lt;li>Erase the internal HD as &lt;code>HFS+ (Journaled, Encrypted)&lt;/code> and set a disk password&lt;/li>
&lt;li>Install OS X onto the internal disk&lt;/li>
&lt;li>During setup, use Migration Assistant to copy clone containing previous install data from backup disk&lt;/li>
&lt;/ol>
&lt;p>This worked great in the end, once I&amp;rsquo;d recompiling various utilities I had installed. (Downside of moving from one CPU arch to another - can&amp;rsquo;t just copy all compiled binaries over.)&lt;/p>
&lt;p>However, I failed at step 2 above and entered &amp;ldquo;password&amp;rdquo; as my disk password since it was only intended to be temporary. Usually OS X&amp;rsquo;s full disk encryption (FileVault 2) allows the machine users to unlock the disk, and not a standalone password. Due to the slightly odd way I setup the machine, I had the option of either using the disk password or my user account&amp;rsquo;s password.&lt;/p>
&lt;p>Having hunted around trying to find how to change or remove this disk password and leave only my users password, I finally stumbled across the magic incantations in an apple discussion thread asking &lt;a href="https://discussions.apple.com/thread/5105759?start=0&amp;amp;tstart=0">How to disable &amp;ldquo;Disk Password&amp;rdquo; on boot?&lt;/a>.&lt;/p>
&lt;p>The magic incantations are as follows:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>List all the passwords that can currently unlock the drive&lt;/p>
&lt;p>&lt;strong>Make sure there is a second password listed or removing the disk password will lock you out of the disk&lt;/strong>.&lt;/p>
&lt;pre>&lt;code> $ sudo fdesetup list -extended
ESCROW UUID TYPE USER
28376DDE-B6E1-48BE-A06F-4212067581D6 Disk Passphrase User
4DBF8CEF-40F7-4F00-902F-A47AA643C656 OS User caius
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Note the UUID of the &amp;ldquo;Disk Passphrase&amp;rdquo; entry, and remove that from the list&lt;/p>
&lt;pre>&lt;code> sudo fdesetup remove -uuid 28376DDE-B6E1-48BE-A06F-4212067581D6
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>List the passwords again to make sure the Disk Passphrase entry was removed&lt;/p>
&lt;pre>&lt;code> $ sudo fdesetup list -extended
ESCROW UUID TYPE USER
4DBF8CEF-40F7-4F00-902F-A47AA643C656 OS User caius
&lt;/code>&lt;/pre>
&lt;/li>
&lt;/ol>
&lt;p>Hey presto, only your user is left being able to unlock the disk.&lt;/p></description></item><item><title>Find dependencies blocking rails upgrades</title><link>https://caiustheory.com/find-dependencies-blocking-rails-upgrades/</link><pubDate>Wed, 10 Aug 2016 11:39:00 +0000</pubDate><guid>https://caiustheory.com/find-dependencies-blocking-rails-upgrades/</guid><description>&lt;p>The initial pain point when upgrading a rails app is figuring out which of your dependencies are blocking you upgrading the actual &lt;code>rails&lt;/code> gem (&amp;amp; immediate dependencies, actionpack, etc.). One way to start this is to update the rails dependency in your &lt;code>Gemfile&lt;/code> and run &lt;code>bundle update rails&lt;/code>. Then check the error output &lt;em>(it never works first time…)&lt;/em> to see which gems are blocking the upgrade. Repeat, rinse until it works.&lt;/p>
&lt;p>I figured I&amp;rsquo;d cheat a little and eyeball the &lt;code>Gemfile.lock&lt;/code> to see which gems had an explicit dependency pinning rails (or actionpack, activejob, etc) to a version lower than I want to upgrade to, so I could get an idea of what needs to be upgraded without having to do them all one-by-one.&lt;/p>
&lt;p>Then instead of eyeballing &lt;code>Gemfile.lock&lt;/code>, I wrote an awk script to pull out the interesting dependencies (ie, anything that depends on rails gems) so I just have to check which versions they depend on by hand.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-awk" data-lang="awk">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Reads a Gemfile.lock and outputs all dependencies that depend on rails&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">BEGIN&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parent&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parent_printed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">rails_gems&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;^(rail(s|ties)|action(mailer|pack|view)|active(job|model|record|support))$&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># We only want the specs from the GEM section&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">NR&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">$&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">~&lt;/span> &lt;span class="sr">/GEM/&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">next&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">$&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">exit&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Skip parent gems we don&amp;#39;t care about (rails itself…)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">$&lt;/span>&lt;span class="mi">0&lt;/span> &lt;span class="o">~&lt;/span> &lt;span class="sr">/^ {4}[^ ]/&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">$&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">~&lt;/span> &lt;span class="nx">rails_gems&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parent&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parent_printed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Parent gems that aren&amp;#39;t part of rails core&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Store the name to be printed if we match below&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">$&lt;/span>&lt;span class="mi">0&lt;/span> &lt;span class="o">~&lt;/span> &lt;span class="sr">/^ {4}[^ ]/&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parent&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">$&lt;/span>&lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parent_printed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># If the nested gem (6 space prefix) matches rails-names and we have a parent value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># set then we print them out - making sure to only print the parent once&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">$&lt;/span>&lt;span class="mi">0&lt;/span> &lt;span class="o">~&lt;/span> &lt;span class="sr">/^ {6}[^ ]/&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">$&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">~&lt;/span> &lt;span class="nx">rails_gems&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">parent&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">parent_printed&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parent_printed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">print&lt;/span> &lt;span class="nx">parent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">print&lt;/span> &lt;span class="o">$&lt;/span>&lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Run it against your &lt;code>Gemfile.lock&lt;/code> for the app you&amp;rsquo;re upgrading:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">awk -f rails5.awk Gemfile.lock
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And you&amp;rsquo;ll get output like this, to run through and see if any of the dependencies are pinning to lower versions than you need.&lt;/p>
&lt;pre tabindex="0">&lt;code> coffee-rails (4.0.1)
railties (&amp;gt;= 4.0.0, &amp;lt; 5.0)
factory_girl (4.4.0)
activesupport (&amp;gt;= 3.0.0)
factory_girl_rails (4.4.1)
railties (&amp;gt;= 3.0.0)
globalid (0.3.7)
activesupport (&amp;gt;= 4.1.0)
google-api-client (0.8.6)
activesupport (&amp;gt;= 3.2)
jquery-rails (3.1.4)
railties (&amp;gt;= 3.0, &amp;lt; 5.0)
jquery-ui-rails (5.0.5)
railties (&amp;gt;= 3.2.16)
rails-deprecated_sanitizer (1.0.3)
activesupport (&amp;gt;= 4.2.0.alpha)
rails-dom-testing (1.0.7)
activesupport (&amp;gt;= 4.2.0.beta, &amp;lt; 5.0)
rspec-rails (3.4.2)
actionpack (&amp;gt;= 3.0, &amp;lt; 4.3)
activesupport (&amp;gt;= 3.0, &amp;lt; 4.3)
railties (&amp;gt;= 3.0, &amp;lt; 4.3)
sass-rails (4.0.5)
railties (&amp;gt;= 4.0.0, &amp;lt; 5.0)
sprockets-rails (2.3.3)
actionpack (&amp;gt;= 3.0)
activesupport (&amp;gt;= 3.0)
&lt;/code>&lt;/pre>&lt;p>In this case, I&amp;rsquo;m trying to take this app to rails 5.0, so all the ones specifying &lt;code>&amp;lt; 5&lt;/code> and &lt;code>&amp;lt; 4.3&lt;/code> need upgrading beforehand.&lt;/p></description></item><item><title>SmartOS Recovery mount /usbkey</title><link>https://caiustheory.com/smartos-recovery-mount-usbkey/</link><pubDate>Mon, 25 Jul 2016 17:59:00 +0000</pubDate><guid>https://caiustheory.com/smartos-recovery-mount-usbkey/</guid><description>&lt;p>Recently I managed to hose a box in a perfectly self-inflicted storm of idiocy. Imagine a SmartOS server with the following issues:&lt;/p>
&lt;ul>
&lt;li>Root password not noted down anywhere&lt;/li>
&lt;li>&lt;code>/usbkey/config&lt;/code> edited badly, meaning the network settings are wrong&lt;/li>
&lt;li>Rebooting the server to apply some other settings&lt;/li>
&lt;/ul>
&lt;p>Needless to say, this caused a tiny issue in the server doing what it&amp;rsquo;s supposed to. Luckily I had access to a KVM remote console for the box and the following worked.&lt;/p>
&lt;p>I brought the machine up, choosing the second option for recovery at the grub menu. Waited for a login prompt, then logged in with &lt;code>root&lt;/code>/&lt;code>root&lt;/code>.&lt;/p>
&lt;p>Realised quite quickly that &lt;code>/usbkey&lt;/code> must be persisted on the &lt;code>zones&lt;/code> zfs pool otherwise the configuration would be lost after shutdown, so imported the correct pool, created a directory to mount into and then mounted the zfs share.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">zpool import zones
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir /usbkey
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mount -F zfs zones/usbkey /usbkey
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Much Wenlock Triathlon 2016</title><link>https://caiustheory.com/much-wenlock-triathlon-2016/</link><pubDate>Sun, 10 Jul 2016 16:00:00 +0000</pubDate><guid>https://caiustheory.com/much-wenlock-triathlon-2016/</guid><description>&lt;p>&lt;strong>500m Pool Swim: 00:11:34&lt;/strong>&lt;/p>
&lt;p>Felt good setting off, within a couple of lengths felt like I had no energy. Didn’t have enough to eat/drink during the morning before starting, really makes a huge difference once you set off. Must remember to replace my goggles at some point too, the strap comes loose without warning.&lt;/p>
&lt;p>&lt;strong>Transition 1: 00:03:06&lt;/strong>&lt;/p>
&lt;p>Rough time for transition. Legs felt good as soon as I was out the pool. Got my kit on without too much trouble, although taking a t-shirt style cycling top instead of a full zip jacket was a mistake—forgot I’d be putting it on wet. Had a gel in transition in the hope it would give me some energy.&lt;/p>
&lt;p>&lt;strong>19km Cycle: 00:48:03&lt;/strong>&lt;/p>
&lt;p>Lovely start to the cycle route, massive downhill on recently resurfaced roads for the most part. Best part of the cycle ride, with the rest of the route consisting of climbing back up to the start. Couple of nasty steep hills I had to walk sections of, for all I fitted lower gears they still weren&amp;rsquo;t low enough given my lack of bike fitness currently.&lt;/p>
&lt;p>&lt;strong>Transition 2: 00:06:57&lt;/strong>&lt;/p>
&lt;p>Bike racked easily, shoes swapped, gel necked and a couple of Lucozade bottles clutched and off to run. Took on another gel.&lt;/p>
&lt;p>&lt;strong>7km Run: 01:04:37&lt;/strong>&lt;/p>
&lt;p>Needed all the fluid I carried, didn&amp;rsquo;t take anything else during the run and felt no less energetic than the other disciplines. Legs didn&amp;rsquo;t really hurt, just felt like lead and had no power. Route was basically a mini trail run then up a tarmac road to the turning point then head back via trail run to finish. Adopted a walk/run approach.&lt;/p>
&lt;p>&lt;strong>Total: 02:14:17&lt;/strong>&lt;/p>
&lt;p>Certainly the hardest triathlon I&amp;rsquo;ve done, and I&amp;rsquo;m probably at my least fittest compared to any of the others I&amp;rsquo;ve done to boot. The location was lovely, the weather was pretty decent (sunny but not too hot). Don&amp;rsquo;t feel like I was beaten by it, but definitely haven&amp;rsquo;t given it my best. One to redo next year and train towards.&lt;/p></description></item><item><title>Setup DHCP interface in FreeBSD</title><link>https://caiustheory.com/setup-dhcp-interface-in-freebsd/</link><pubDate>Tue, 05 Jul 2016 10:00:00 +0000</pubDate><guid>https://caiustheory.com/setup-dhcp-interface-in-freebsd/</guid><description>&lt;p>Given a FreeBSD instance without a configured network interface that you&amp;rsquo;d like to configure, first check what the name of the interface you want to configure is with &lt;code>ifconfig&lt;/code>. (Mine is &lt;code>em0&lt;/code> in this instance.)&lt;/p>
&lt;p>Then we need to add the configuration telling services that we want to use DHCP for this interface, and setting up our default router (use your IP, not mine!) too:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">cat &amp;gt;&amp;gt; rc.conf &lt;span class="s">&amp;lt;&amp;lt;CONF
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">ifconfig_em0=&amp;#34;DHCP&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">default_router=&amp;#34;192.168.1.1&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">CONF&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then we need to start &lt;code>dhclient&lt;/code> on the given interface:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">service dhclient start em0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hey presto, you should see dhclient finding a DHCP server and being handed an IP address for &lt;code>em0&lt;/code>.&lt;/p></description></item><item><title>SoundCloud RSS Feeds</title><link>https://caiustheory.com/soundcloud-rss-feeds/</link><pubDate>Thu, 26 Nov 2015 23:33:37 +0000</pubDate><guid>https://caiustheory.com/soundcloud-rss-feeds/</guid><description>&lt;p>&lt;a href="https://soundcloud.com">SoundCloud&lt;/a> appears to have gained popularity in recent times for hosting podcasts on. As a consumer of their service they&amp;rsquo;re pretty good at everything except having a visible RSS feed on a profile page for a show! If I want to listen to a show in my podcast app of choice, an RSS feed is the easiest way for me to achieve that.&lt;/p>
&lt;p>Turns out SoundCloud &lt;em>do&lt;/em> have RSS feeds, they&amp;rsquo;re just well hidden and unfindable from the profile page itself. Thankfully, you can construct the URL for it from information on the profile page, and here&amp;rsquo;s a bookmarklet that will do it for you:&lt;/p>
&lt;pre>&lt;code>javascript:var%20userURI;var%20metaTags=document.getElementsByTagName(
%22meta%22);for(var%20i=0;i&amp;lt;metaTags.length;i++){t=metaTags[i];if(
t.attributes[%22property%22]&amp;amp;&amp;amp;t.attributes[%22property%22].value==
%22al:ios:url%22){userURI=t.content;}}if(userURI){u=userURI.split(%22//%22)[1];
window.location=%22http://feeds.soundcloud.com/users/soundcloud:%22+u+
%22/sounds.rss%22;}
&lt;/code>&lt;/pre>
&lt;p>Or as a &lt;a href="">handy link&lt;/a> to copy to your bookmarks bar. Simply click/run that when on a SoundCloud profile page and you&amp;rsquo;ll be taken to the RSS Feed URL.&lt;/p></description></item><item><title>exec(3) in Go</title><link>https://caiustheory.com/exec-3-in-go/</link><pubDate>Sat, 31 Jan 2015 09:37:37 +0000</pubDate><guid>https://caiustheory.com/exec-3-in-go/</guid><description>&lt;p>Using &lt;a href="http://man7.org/linux/man-pages/man3/exec.3.html">exec(3)&lt;/a> from Go is simple enough, once you figure out to look in the &lt;a href="http://golang.org/pkg/syscall/">syscall&lt;/a> package and how to pass arguments to the new command.&lt;/p>
&lt;p>As a simple example, I&amp;rsquo;m going to exec &lt;code>/bin/echo&lt;/code> with a hardcoded string from the go binary. &lt;em>The program built here is in the &lt;a href="https://github.com/caius/gecho">gecho&lt;/a> (Gecko, geddit?) git repo, which each stage as a commit.&lt;/em>&lt;/p>
&lt;p>In our main function lets setup some variables we&amp;rsquo;re going to need for arguments to &lt;code>syscall.Exec&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cmdPath&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="s">&amp;#34;/bin/echo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cmdArgs&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;Hello&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;World&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cmdEnv&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>(We could use &lt;code>os.Environ()&lt;/code> for &lt;code>cmdEnv&lt;/code> to take the ENV from the go binary, but we don&amp;rsquo;t require anything from the environmnt here so it doesn&amp;rsquo;t matter that we aren&amp;rsquo;t.)&lt;/em>&lt;/p>
&lt;p>Now we have the arguments for &lt;code>syscall.Exec&lt;/code>, lets add that in and see what happens:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">syscall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Exec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">cmdPath&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">cmdArgs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">cmdEnv&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">panic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">err&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And running the file (&lt;code>go run gecho.go&lt;/code> compiles &amp;amp; runs for us) gives the following output:&lt;/p>
&lt;pre>&lt;code>World
&lt;/code>&lt;/pre>
&lt;p>Err, say what now? Where&amp;rsquo;s &amp;ldquo;Hello&amp;rdquo; gone?!&lt;/p>
&lt;p>Took me a while to figure this out when I originally ran into this. The answer is staring us right in the face if we go look at the &lt;a href="http://golang.org/pkg/syscall/#Exec">syscall.Exec docs&lt;/a>. Lets have a look at the function signature, argument names and all:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">Exec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">argv0&lt;/span> &lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">argv&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">envv&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">err&lt;/span> &lt;span class="kt">error&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hmm. The first argument is &lt;code>argv0&lt;/code> (and a string), rather than &lt;code>binaryPath&lt;/code> or something similar. The second argument is then &lt;code>argv&lt;/code> and an array of strings.&lt;/p>
&lt;p>&lt;em>At this point I remember that the first element of &lt;code>argv&lt;/code> in other runtimes is the name of the binary or command invoked - &lt;code>$0&lt;/code> in a bash script is the name of the script for example.&lt;/em>&lt;/p>
&lt;p>The answer is simple. &lt;code>cmdArgs&lt;/code> in our script should have &lt;code>/bin/echo&lt;/code> as the first element, and then we pass &lt;code>cmdArgs[0], cmdArgs&lt;/code> as the first two arguments to &lt;code>syscall.Exec&lt;/code>. Lets give that a go:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cmdArgs&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;/bin/echo&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Hello&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;World&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cmdEnv&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">syscall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Exec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">cmdArgs&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nx">cmdArgs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">cmdEnv&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">panic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">err&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And running it (&lt;code>go run gecho.go&lt;/code> remember) gives the expected output:&lt;/p>
&lt;pre>&lt;code>Hello World
&lt;/code>&lt;/pre>
&lt;p>Excellent. Now I just need to remember &lt;code>argv&lt;/code> contains the command name as &lt;code>argv[0]&lt;/code> and we&amp;rsquo;re golden.&lt;/p>
&lt;hr>
&lt;p>There is also the &lt;a href="http://golang.org/pkg/os/exec/">os/exec&lt;/a> package in the stdlib, which is intended for executing other binaries as child processes from what I can tell. Tellingly, when you create a &lt;code>exec.Cmd&lt;/code> struct with &lt;code>exec.Command()&lt;/code> you give it the name as first argument, and args as following arguments. Then it has the following snippet in the documentation:&lt;/p>
&lt;blockquote>
&lt;p>The returned Cmd&amp;rsquo;s Args field is constructed from the command name followed by the elements of arg, so arg should not include the command name itself. For example, &lt;code>Command(&amp;quot;echo&amp;quot;, &amp;quot;hello&amp;quot;)&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;p>So &lt;code>cmd := exec.Command(&amp;quot;echo&amp;quot;, &amp;quot;hello&amp;quot;); cmd.Args&lt;/code> would return &lt;code>[]string{&amp;quot;echo&amp;quot;, &amp;quot;hello&amp;quot;}&lt;/code> - which is recognisable as what we have to pass to &lt;code>syscall.Exec&lt;/code>!&lt;/p></description></item><item><title>Changing hostname in SmartOS Zone</title><link>https://caiustheory.com/changing-hostname-in-smartos-zone/</link><pubDate>Thu, 18 Dec 2014 10:00:00 +0000</pubDate><guid>https://caiustheory.com/changing-hostname-in-smartos-zone/</guid><description>&lt;p>Given a non-global zone in SmartOS that we want to change the hostname of, we need to make sure to edit the following files to change it:&lt;/p>
&lt;ul>
&lt;li>&lt;code>/etc/hosts&lt;/code>&lt;/li>
&lt;li>&lt;code>/etc/nodename&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>A quick way to do that is with &lt;code>sed&lt;/code> &lt;em>(renaming &amp;ldquo;fred&amp;rdquo; to &amp;ldquo;beth&amp;rdquo; here)&lt;/em>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sed -e &lt;span class="s1">&amp;#39;s/fred/beth/g&amp;#39;&lt;/span> -i /etc/hosts /etc/nodename
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then shutdown &amp;amp; start the zone &lt;em>(from my testing a restart doesn&amp;rsquo;t apply it)&lt;/em>.&lt;/p></description></item><item><title>Install Rubinius on OS X</title><link>https://caiustheory.com/install-rubinius-on-os-x/</link><pubDate>Wed, 05 Nov 2014 12:50:16 +0000</pubDate><guid>https://caiustheory.com/install-rubinius-on-os-x/</guid><description>&lt;p>Using &lt;a href="https://github.com/postmodern/ruby-install/">ruby-install&lt;/a>, &lt;a href="http://brew.sh/">homebrew&lt;/a> building it for use with &lt;a href="https://github.com/postmodern/chruby/">chruby&lt;/a>, here&amp;rsquo;s how I install &lt;a href="http://rubini.us/">Rubinius&lt;/a> under Yosemite (works for Mavericks as well.)&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Make sure llvm is installed&lt;/p>
&lt;pre>&lt;code> $ brew install llvm
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Prepend the homebrew-installed llvm tools to your path&lt;/p>
&lt;pre>&lt;code> $ export PATH=&amp;quot;$(brew --prefix llvm)/bin:$PATH&amp;quot;
# Or, for ZSH
$ path=( $(brew --prefix llvm)/bin $path )
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Install rubinius, v2.3.0 at the time of writing&lt;/p>
&lt;pre>&lt;code> $ ruby-install rbx 2.3.0
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Open a fresh shell once that&amp;rsquo;s built, and you should be able to switch to rbx!&lt;/p>
&lt;pre>&lt;code> $ chruby rbx
$ ruby -v
rubinius 2.3.0 (2.1.0 9d61df5d 2014-10-31 3.5.0 JI) [x86_64-darwin14.0.0]
&lt;/code>&lt;/pre>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;p>&lt;em>There is also a homebrew tap for rubinius which should also work instead of the above. I couldn&amp;rsquo;t get it working on one of my laptops though, which is why I was installing by hand using the above instead. The tap is at &lt;a href="https://github.com/rubinius/homebrew-apps/">https://github.com/rubinius/homebrew-apps/&lt;/a> and &lt;a href="https://twitter.com/brixen/status/529725881498226688">https://twitter.com/brixen/status/529725881498226688&lt;/a> explains install steps.&lt;/em>&lt;/p></description></item><item><title>Changing root password in global zone</title><link>https://caiustheory.com/changing-root-password-in-global-zone/</link><pubDate>Sun, 19 Oct 2014 17:44:20 +0000</pubDate><guid>https://caiustheory.com/changing-root-password-in-global-zone/</guid><description>&lt;p>SmartOS mounts &lt;code>/etc/shadow&lt;/code> from &lt;code>/usbkey/shadow&lt;/code> so we can change the root password for the global zone after install. Here&amp;rsquo;s how:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Fire up a console or ssh session as root in the global zone&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Check the existing permissions on the file&lt;/p>
&lt;pre>&lt;code> $ ls -l /usbkey/shadow
-r-------- 1 root root 560 Oct 19 16:45 /usbkey/shadow
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Make the file writable&lt;/p>
&lt;pre>&lt;code> $ chmod 600 /usbkey/shadow
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Fire up &lt;code>vi&lt;/code> to edit the file&lt;/p>
&lt;pre>&lt;code> $ vi /usbkey/shadow
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Edit the line containing root to change the crypted password. See &lt;a href="https://us-east.manta.joyent.com/smartosman/public/man4/shadow.4.html">&lt;code>shadow(4)&lt;/code>&lt;/a> if you need help with the format of &lt;code>/etc/shadow&lt;/code> &amp;amp; use &lt;code>/usr/lib/cryptpass&lt;/code> to generate a hash for the password you desire. &lt;em>(Remember to clean the bash history!)&lt;/em>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Save the file and exit &lt;code>vi&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Make the file readonly again&lt;/p>
&lt;pre>&lt;code> $ chmod 400 /usbkey/shadow
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Double check permissions are correct on the file again&lt;/p>
&lt;pre>&lt;code> $ ls -l /usbkey/shadow
-r-------- 1 root root 560 Oct 19 16:49 /usbkey/shadow
&lt;/code>&lt;/pre>
&lt;/li>
&lt;/ol>
&lt;p>Job done. Verify by logging in as root (invoking &lt;code>/usr/bin/login&lt;/code> from an ssh session makes this easy to verify.)&lt;/p></description></item><item><title>Compiling SmartOS for AMD processors</title><link>https://caiustheory.com/compiling-smartos-for-amd-processors/</link><pubDate>Sun, 28 Sep 2014 10:00:00 +0000</pubDate><guid>https://caiustheory.com/compiling-smartos-for-amd-processors/</guid><description>&lt;p>There&amp;rsquo;s a few community-provided patches for SmartOS that enable KVM on AMD processors amongst other things, and given the HP Microserver has an AMD processor, that&amp;rsquo;s quite useful for turning it into a better lab server. The main &lt;a href="http://imgapi.uqcloud.net/builds">list of so called &amp;ldquo;eait&amp;rdquo; builds&lt;/a> was hiccuping when I tried to download the latest, and all I could find was a 20140812T062241Z image &lt;a href="http://builds.smartos.skylime.net">here&lt;/a>.&lt;/p>
&lt;p>The source code for the eait builds is maintained at &lt;a href="https://github.com/arekinath/smartos-live">https://github.com/arekinath/smartos-live&lt;/a>, and you can see the patches applied on top of the normal SmartOS master by going to &lt;a href="https://github.com/arekinath/smartos-live/compare/joyent:master...eait">https://github.com/arekinath/smartos-live/compare/joyent:master...eait&lt;/a>.&lt;/p>
&lt;p>So here&amp;rsquo;s how to use SmartOS to compile a more up to date AMD-friendly Smartos!&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Grab the latest multiarch SmartOS image (which &lt;strong>has&lt;/strong> to be used, or the compile will fail.) The latest at the time of writing was &lt;code>4aec529c-55f9-11e3-868e-a37707fcbe86&lt;/code>, so that&amp;rsquo;s what I&amp;rsquo;ll use.&lt;/p>
&lt;pre>&lt;code> imgadm import 4aec529c-55f9-11e3-868e-a37707fcbe86
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Spin up a zone for us to build in (the &lt;a href="http://wiki.smartos.org/display/DOC/Building+SmartOS+on+SmartOS">Building SmartOS on SmartOS&lt;/a> page has extra info about this):&lt;/p>
&lt;pre>&lt;code> echo '{
&amp;quot;alias&amp;quot;: &amp;quot;platform-builder&amp;quot;,
&amp;quot;brand&amp;quot;: &amp;quot;joyent&amp;quot;,
&amp;quot;dataset_uuid&amp;quot;: &amp;quot;4aec529c-55f9-11e3-868e-a37707fcbe86&amp;quot;,
&amp;quot;max_physical_memory&amp;quot;: 32768,
&amp;quot;quota&amp;quot;: 0,
&amp;quot;tmpfs&amp;quot;: 8192,
&amp;quot;fs_allowed&amp;quot;: &amp;quot;ufs,pcfs,tmpfs&amp;quot;,
&amp;quot;maintain_resolvers&amp;quot;: true,
&amp;quot;resolvers&amp;quot;: [
&amp;quot;8.8.8.8&amp;quot;,
&amp;quot;8.8.4.4&amp;quot;
],
&amp;quot;nics&amp;quot;: [
{
&amp;quot;nic_tag&amp;quot;: &amp;quot;admin&amp;quot;,
&amp;quot;ip&amp;quot;: &amp;quot;dhcp&amp;quot;,
&amp;quot;primary&amp;quot;: true
}
],
&amp;quot;internal_metadata&amp;quot;: {
&amp;quot;root_pw&amp;quot;: &amp;quot;password&amp;quot;,
&amp;quot;admin_pw&amp;quot;: &amp;quot;password&amp;quot;
}
}' | vmadm create
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Login to the created zone:&lt;/p>
&lt;pre>&lt;code> zlogin &amp;lt;uuid from `vmadm create` output&amp;gt;
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Update the image to the latest packages, etc:&lt;/p>
&lt;pre>&lt;code> pkgin -y update &amp;amp;&amp;amp; pkgin -y full-upgrade
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Install a few images we&amp;rsquo;ll need to compile &amp;amp; package SmartOS:&lt;/p>
&lt;pre>&lt;code> pkgin install scmgit cdrtools pbzip2
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Grab the source code of the fork containing the patches we want, from &lt;a href="https://github.com/arekinath/smartos-live">arekinath/smartos-live&lt;/a>&lt;/p>
&lt;pre>&lt;code> git clone https://github.com/arekinath/smartos-live
cd smartos-live
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>&lt;em>Optional&lt;/em>: Edit &lt;code>src/Makefile.defs&lt;/code> and change &lt;code>PARALLEL = -j$(MAX_JOBS)&lt;/code> to &lt;code>PARALLEL = -j8&lt;/code> to do less at once. (Microserver only has a dual core CPU!)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Copy the configure definition into the right place and start configuration:&lt;/p>
&lt;pre>&lt;code> cp {sample.,}configure.smartos
./configure
&lt;/code>&lt;/pre>
&lt;p>&lt;em>(You&amp;rsquo;ll probably get asked to accept the java license during configuration, so keep half an eye on it)&lt;/em>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Once configure has completed (which doesn&amp;rsquo;t take &lt;em>too&lt;/em> long, 15 minutes or so), start building:&lt;/p>
&lt;pre>&lt;code> gmake world &amp;amp;&amp;amp; gmake live
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Once the build is successfully finished, time to package an iso &amp;amp; usb image:&lt;/p>
&lt;pre>&lt;code>export LC_ALL=C
tools/build_iso
tools/build_usb
&lt;/code>&lt;/pre>
&lt;/li>
&lt;/ol>
&lt;p>Hey presto, you&amp;rsquo;ve a freshly built AMD-friendly SmartOS build to flash to a USB key / put on your netboot server and boot your Microserver from!&lt;/p>
&lt;hr>
&lt;p>&lt;strong>References&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://wiki.smartos.org/display/DOC/Building+SmartOS+on+SmartOS">http://wiki.smartos.org/display/DOC/Building+SmartOS+on+SmartOS&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/arekinath/smartos-live">https://github.com/arekinath/smartos-live&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>The People's Triathlon 2014</title><link>https://caiustheory.com/the-peoples-triathlon-2014/</link><pubDate>Mon, 11 Aug 2014 10:00:00 +0000</pubDate><guid>https://caiustheory.com/the-peoples-triathlon-2014/</guid><description>&lt;p>My first Olympic distance triathlon, and the first time I&amp;rsquo;ve ever run 10km to boot.&lt;/p>
&lt;p>&lt;strong>1500m Open Water (Freshwater Lake) Swim: 00:38:08&lt;/strong>&lt;/p>
&lt;p>Equally happy and upset with my swim. Basically everything went well except my wetsuit, must get a proper swimming one (possibly sleeveless) before my next wetsuit event. Having to get out at the end of each lap and run down the bank to re-enter the water was a bit strange but not too bad. Worst bit of that was diving back in and forgetting to look down - goggles bruised the edge of my eyesocket!&lt;/p>
&lt;p>&lt;strong>Transition 1: 00:03:53&lt;/strong>&lt;/p>
&lt;p>Took this at a sedate pace, didn&amp;rsquo;t rush but didn&amp;rsquo;t dawdle either. Perhaps could&amp;rsquo;ve gone a bit quicker but not unhappy with it. Found bike OK this time, although chain fell off as I went to mount which was slightly annoying.&lt;/p>
&lt;p>&lt;strong>40km Cycle: 01:28:49&lt;/strong>&lt;/p>
&lt;p>Started off really badly, managed to knock my watch from cycle into Transition 2 before I&amp;rsquo;d gotten out the car park. Had to reset it quickly into just bike mode from multisport mode which wasn&amp;rsquo;t too bad to be fair, just annoying. Having done the route in training was a &lt;em>big&lt;/em> help on the day, I was aiming for about the time I did it in. Didn&amp;rsquo;t push too hard on the two hills (one of which looks deceptively easy). Very happy with my time and more importantly how little effort it was comparatively.&lt;/p>
&lt;p>&lt;strong>Transition 2: 00:01:28&lt;/strong>&lt;/p>
&lt;p>Quicker than T1, as normal. Got my shit on quickly, didn&amp;rsquo;t forget anything and even managed to get my watch in run mode whilst jogging to the exit of the transition area.&lt;/p>
&lt;p>&lt;strong>10km Run: 01:18:40&lt;/strong>&lt;/p>
&lt;p>The bit I was dreading the most. Very very happy with my performance here though. Walked about 90 seconds of the whole thing and kept plodding away the rest of the time. Given the furthest I&amp;rsquo;d run solidly in training was about 5.5km, I was exceptionally happy to just keep plodding the whole time. Managed to not take on liquid for the third lap, which lead to some impressive cramping in my right quad, so making sure I take liquid on is a definite thing to watch out for in future. And amazingly I wasn&amp;rsquo;t even tail end charlie (not that it really matters, given I race the clock, not other people. But still.)&lt;/p>
&lt;p>&lt;strong>Total: 03:30:51&lt;/strong>&lt;/p>
&lt;p>There&amp;rsquo;s a tiny part of me that&amp;rsquo;s gutted I didn&amp;rsquo;t manage it in under 3:30 hours, but what&amp;rsquo;s 51 seconds over that period of time. More importantly, I completed the bloody thing! Especially happy with the run, enjoyed the cycle even if it was trying to drown us (there was 6&amp;quot; deep standing water on one of the roundabouts by the end), and mostly happy with my swim.&lt;/p>
&lt;p>Looking forward to returning next year and beating 3:30!&lt;/p></description></item><item><title>Solve volume down button not working on iPhone 5</title><link>https://caiustheory.com/solve-volume-down-button-not-working-on-iphone-5/</link><pubDate>Tue, 01 Jul 2014 11:31:39 +0000</pubDate><guid>https://caiustheory.com/solve-volume-down-button-not-working-on-iphone-5/</guid><description>&lt;p>I noticed this morning that my volume down button (-) wasn&amp;rsquo;t working on my iPhone 5 running iOS 7. Pushing the physical button in didn&amp;rsquo;t change the volume. The volume up button increased the volume successfully still.&lt;/p>
&lt;p>As is my normal first step debugging iPhone weirdness, I rebooted the phone by turning it off, leaving it off for a few seconds, then booting it back up with the power button. Once powered off and on in this way, the volume down key still didn&amp;rsquo;t decrease the volume.&lt;/p>
&lt;p>Fearing a physical button issue at this point, I turned to google for suggestions on what else to try. Running across &lt;a href="https://discussions.apple.com/thread/4894152">this thread&lt;/a> on Apple&amp;rsquo;s discussion forums, I tried out the solution in there.&lt;/p>
&lt;ol>
&lt;li>Open &amp;ldquo;Settings&amp;rdquo;&lt;/li>
&lt;li>Scroll down and tap on &amp;ldquo;General&amp;rdquo;&lt;/li>
&lt;li>Tap on &amp;ldquo;Accessibility&amp;rdquo;&lt;/li>
&lt;li>Scroll down to the bottom and tap on &amp;ldquo;AssistiveTouch&amp;rdquo;&lt;/li>
&lt;li>Tap the toggle for AssistiveTouch to turn it on, and you should see a little icon appear on screen (white circle contained in a dark grey rounded square)&lt;/li>
&lt;li>Tap the AssistiveTouch icon (was in the top left corner on screen for me)&lt;/li>
&lt;li>Tap on &amp;ldquo;Device&amp;rdquo;&lt;/li>
&lt;li>Tap &amp;ldquo;Volume Down&amp;rdquo; a bunch of times and you should see the volume being turned down&lt;/li>
&lt;li>Tap outside the AssistiveTouch dialog to close it&lt;/li>
&lt;li>Try pushing the physical Volume Down button&lt;/li>
&lt;/ol>
&lt;p>In my case, following these steps made my physical volume down button start working again. Makes me wonder if the solution author on the apple discussion thread is right, in that this is a software issue and forcing a volume down action through the on-screen interface makes it remember that there&amp;rsquo;s a physical button to respond to as well.&lt;/p>
&lt;p>Either way, I can stop deafening myself whenever I receive a notification now!&lt;/p></description></item><item><title>Compile &amp; run swift files directly</title><link>https://caiustheory.com/compile-run-swift-files-directly/</link><pubDate>Fri, 06 Jun 2014 14:32:18 +0000</pubDate><guid>https://caiustheory.com/compile-run-swift-files-directly/</guid><description>&lt;p>Turns out you can run a swift file without having to compile it into a binary somewhere and then run that binary. Makes swift behave a bit more like a scripting language like ruby or python when you need it to.&lt;/p>
&lt;p>Using the &lt;code>xcrun&lt;/code> binary, we can reach into the current Xcode &lt;code>/bin&lt;/code> folder and run binaries within there. So &lt;code>xcrun swift&lt;/code> lets you run the swift binary to compile files for instance. If you view the help with &lt;code>-h&lt;/code>, there&amp;rsquo;s a useful flag &lt;code>-i&lt;/code> listed there:&lt;/p>
&lt;blockquote>
&lt;p>-i    Immediate mode&lt;/p>
&lt;/blockquote>
&lt;p>Turns out immediate mode means &amp;ldquo;compile &amp;amp; run&amp;rdquo; in the same command, which is what we&amp;rsquo;re after.&lt;/p>
&lt;pre>&lt;code>$ cat hello.swift
println(&amp;quot;Hello World&amp;quot;)
$ xcrun swift -i hello.swift
Hello World
&lt;/code>&lt;/pre>
&lt;p>Bingo. But what if we want to make hello.swift executable and call it directly without having to know it needs the swift binary to call it. Unix lets files define their shebang to say how the file needs to be executed, so lets go for that here too!&lt;/p>
&lt;pre>&lt;code>$ cat hello2.swift
#!/usr/bin/env xcrun swift -i
println(&amp;quot;Hello World 2&amp;quot;)
$ chmod +x hello2.swift
$ ./hello2.swift
Hello World 2
&lt;/code>&lt;/pre>
&lt;p>No more having to fire up Xcode for quick CLI tools, especially ones using the system frameworks!&lt;/p></description></item><item><title>Cheshire Triathlon 2014</title><link>https://caiustheory.com/cheshire-triathlon-2014/</link><pubDate>Mon, 02 Jun 2014 10:00:00 +0000</pubDate><guid>https://caiustheory.com/cheshire-triathlon-2014/</guid><description>&lt;p>Successfully completed my second Sprint Triathlon of the season in Nantwich.&lt;/p>
&lt;p>&lt;strong>500m Swim - 00:10:49&lt;/strong>&lt;/p>
&lt;p>Felt good swimming this. Mixed up my usual breaststroke with some front crawl to overtake and use my legs less towards the end. Think I need to put a shorter time down on paper next time though, was in with people who were swimming much slower than me. (Including one chap who was doing doggy paddle in the deep end and walking as soon as his feet touched bottom. Oh well!) Need to continue with front crawl practice, and aim to do next sprint tri entirely crawl.&lt;/p>
&lt;p>&lt;strong>Transition 1 - 00:02:43&lt;/strong>&lt;/p>
&lt;p>Went well. Ran from pool to bike and felt OK. Kit on without any fuckups. Didn&amp;rsquo;t fall off getting on bike. Winning. Need to practice getting on my bike in shoes at a run though.&lt;/p>
&lt;p>&lt;strong>20km Bike - 00:42:31&lt;/strong>&lt;/p>
&lt;p>10 minutes quicker than same length course last year. (Although a slightly new route this year.) Lost a minute when my water bottle fell out about 12km in though. Barely saw a soul, got stuck at one pedestrian crossing on red. Felt very good on the bike (and finally beat Liam on the same route &amp;amp; day ). Need to fit a tighter bottle carrier to stop the bottle falling out on bumpy roads.&lt;/p>
&lt;p>&lt;strong>Transition 2 - 00:01:21&lt;/strong>&lt;/p>
&lt;p>Came off bike well and ran to shoes. Couldn&amp;rsquo;t find where I&amp;rsquo;d left them, was trying to find Liam&amp;rsquo;s bike as my marker for it, only someone else earlier in the same row had the same bike as him! Wasted 10 seconds looking probably. Need to remember where my stuff is more accurately in future.&lt;/p>
&lt;p>&lt;strong>5km Run - 00:39:03&lt;/strong>&lt;/p>
&lt;p>Boiling hot by the point I started running; didn&amp;rsquo;t feel great in the first few hundred meters and never really got comfortable after that. Walked about 800m of it in total at a guess, really didn&amp;rsquo;t have much left in my legs. Not convinced pushing less on the bike would&amp;rsquo;ve helped my run though. On the plus side, only 7 minutes slower than a training run a couple of weeks ago in similar heat, and this was on grass. Need to continue running at 5km distance, and train on grass as well as tarmac I think.&lt;/p>
&lt;p>&lt;strong>Total time - 01:36:27&lt;/strong>&lt;/p>
&lt;p>8 minutes slower than York a couple of months ago, and felt &lt;em>much&lt;/em> worse on the run. Very happy with my bike &amp;amp; swim though. More run training required!&lt;/p></description></item><item><title>York April 2014 Triathlon</title><link>https://caiustheory.com/york-triathlon-2014/</link><pubDate>Mon, 28 Apr 2014 10:00:00 +0000</pubDate><guid>https://caiustheory.com/york-triathlon-2014/</guid><description>&lt;p>Completed the York sprint distance tri in 1:28:37 total, and didn&amp;rsquo;t die in the process. Split times &amp;amp; my thoughts below..&lt;/p>
&lt;p>&lt;strong>400m Swim: 00:08:08&lt;/strong>&lt;br>
&lt;strong>T1: 00:03:47&lt;/strong>&lt;br>
&lt;strong>18km Bike: 00:38:43&lt;/strong>&lt;br>
&lt;strong>T2: 00:00:58&lt;/strong>&lt;br>
&lt;strong>5km Run: 00:38:08&lt;/strong>&lt;/p>
&lt;p>(Amusingly the official time for my swim was 00:10:10, which then makes my official time for T1 00:00:38; Fastest Swim/Bike transition time in the tri on paper! Ahem.)&lt;/p>
&lt;p>Happy with my swim, not much different from training speed &amp;amp; felt good getting out the pool. T1 was okay, and I remembered to put my tshirt on before my helmet this time! Quite happy with my cycling, got down on the drop bars going downhill with tailwind, and could maintain 16mph uphill on the return leg, the bike itself had a major service 2 weeks ago and I&amp;rsquo;d not really ridden much since that either. Legs responded with life in them coming off the bike, second transition was quicker than expected (elastic laces win!). Moderately happy with the run, was hoping to do it in under 40 minutes (and did), but still felt like I had no more distance/pace left before halfway through. Pushed through to the end okay, and didn&amp;rsquo;t walk at all. Overall very happy for my first sprint distance, and especially happy to be running 5km after swim/bike without walking.&lt;/p>
&lt;p>First event of the season done. Main area to work on is my run, but that&amp;rsquo;s been the case since last season. Winter running training seems to have paid off so far.&lt;/p></description></item><item><title>Rename Google Drive folder on Mac</title><link>https://caiustheory.com/rename-google-drive-folder-on-mac/</link><pubDate>Thu, 06 Mar 2014 15:49:22 +0000</pubDate><guid>https://caiustheory.com/rename-google-drive-folder-on-mac/</guid><description>&lt;ol>
&lt;li>Quit Google Drive app&lt;/li>
&lt;li>Rename &lt;code>~/Google Drive/&lt;/code> to whatever you want&lt;/li>
&lt;li>Open Google Drive and wait for it to complain the folder is missing&lt;/li>
&lt;li>Click the menu item and click the warning item&lt;/li>
&lt;li>Click &amp;ldquo;Locate Folder..&amp;rdquo; button on the right in window that pops up&lt;/li>
&lt;li>Find your renamed folder and hit OK&lt;/li>
&lt;li>There is no step seven&lt;/li>
&lt;/ol></description></item><item><title>Add to iCloud Reading List programmatically</title><link>https://caiustheory.com/add-to-icloud-reading-list-programmatically/</link><pubDate>Mon, 16 Dec 2013 22:26:31 +0000</pubDate><guid>https://caiustheory.com/add-to-icloud-reading-list-programmatically/</guid><description>&lt;p>One piece of a larger puzzle I&amp;rsquo;m trying to solve currently, was how to add a given URL to my Apple &amp;ldquo;&lt;a href="http://www.apple.com/uk/safari/#icloud">Reading List&lt;/a>&amp;rdquo; that is stored in iCloud and synced across all my OS X and iOS devices. More specifically, I wanted to add URLs to the list from my mac running Mavericks (10.9). I had a quick look at the Cocoa APIs and couldn&amp;rsquo;t see anything in OS X to do this. (iOS has an API to do it from Cocoa-land it seems though.)&lt;/p>
&lt;p>I figured &lt;a href="http://www.apple.com/uk/safari/">Safari.app&lt;/a> was the key to getting this done on OS X, given it has the ability itself to add the current page to the reading list, either via a keyboard command, a menu item, or a button in the address bar. One quick mental leap later, and I was wondering if the engineers at Apple had been nice enough to expose that via Applescript for me to take advantage of.&lt;/p>
&lt;p>One quick stop in &amp;ldquo;Script Editor.app&amp;rdquo; later, and I had the Applescript dictionary open for Safari.app. Lo and behold, there is rather handily an Applescript command called &amp;ldquo;add reading list item&amp;rdquo;, which does &lt;strong>exactly&lt;/strong> what I want. It has a few different options you can call it with, depending on whether you want Safari to go populate the title &amp;amp; preview text, or if you want to specify it yourself at save-time.&lt;/p>
&lt;p>As I want to be able to call this from multiple runtimes, I&amp;rsquo;ve chosen to save it as an executable, which leans on &lt;a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/osascript.1.html">&lt;code>osascript&lt;/code>&lt;/a> to run the actual Applescript. And here it is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-applescript" data-lang="applescript">&lt;span class="line">&lt;span class="cl">&lt;span class="c">#!/usr/bin/env osascript&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">on&lt;/span> &lt;span class="nb">run&lt;/span> &lt;span class="nv">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">count&lt;/span> &lt;span class="k">of&lt;/span> &lt;span class="nv">argv&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">tell&lt;/span> &lt;span class="nv">app&lt;/span> &lt;span class="s2">&amp;#34;Safari&amp;#34;&lt;/span> &lt;span class="k">to&lt;/span> &lt;span class="nv">add&lt;/span> &lt;span class="nv">reading&lt;/span> &lt;span class="nv">list&lt;/span> &lt;span class="nb">item&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">item&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="k">of&lt;/span> &lt;span class="nv">argv&lt;/span> &lt;span class="k">as &lt;/span>&lt;span class="nc">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span> &lt;span class="k">if&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span> &lt;span class="nb">run&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Save it as whatever you want (eg. &lt;code>add_to_reading_list&lt;/code>), make it executable (&lt;code>chmod +x add_to_reading_list&lt;/code>), and then run it with the URL you want saving as the first argument.&lt;/p>
&lt;pre>&lt;code>$ add_to_reading_list &amp;quot;http://caius.name/&amp;quot;
$ add_to_reading_list &amp;quot;http://google.com/&amp;quot;
# … etc …
&lt;/code>&lt;/pre>
&lt;p>&lt;em>(Adding support for specifying preview text and title is left as an exercise for the reader!)&lt;/em>&lt;/p>
&lt;p>Have fun reading later!&lt;/p></description></item><item><title>North West Triathlon 2013</title><link>https://caiustheory.com/north-west-triathlon-2013/</link><pubDate>Thu, 12 Sep 2013 10:00:00 +0000</pubDate><guid>https://caiustheory.com/north-west-triathlon-2013/</guid><description>&lt;p>&amp;ldquo;Fun&amp;rdquo; triathlon (super sprint distance) done in Nantwich. First ever Triathlon, 7 months after starting training properly.&lt;/p>
&lt;p>&lt;strong>200m swim: 00:04:08&lt;/strong>&lt;/p>
&lt;p>Despite feeling like I was going super slow. Brine pool was fairly nice.&lt;/p>
&lt;p>&lt;strong>20km bike: 00:52:31&lt;/strong>&lt;/p>
&lt;p>Pretty happy with that, strongest discipline for me anyway.&lt;/p>
&lt;p>&lt;strong>2.5km run: 00:21:08&lt;/strong>&lt;/p>
&lt;p>Walked 2/3s of it at a guess. Really hate running, so happyish with this. Need to work on running over the winter.&lt;/p>
&lt;p>&lt;strong>Total: 1h 17m 47s&lt;/strong>&lt;/p>
&lt;p>BOOYA. Enjoyable. Pretty damn happy with that (had a vague plan of being under 1h30m. So yay.)&lt;/p></description></item><item><title>Happy Villanelle</title><link>https://caiustheory.com/happy-villanelle/</link><pubDate>Fri, 22 Feb 2013 15:15:03 +0000</pubDate><guid>https://caiustheory.com/happy-villanelle/</guid><description>&lt;p>The writing group that Carole and Liberty belong to had a homework this month to write a Villanelle. It&amp;rsquo;s a very specific kind of poem, written to both a repeating line structure and a rhyming pattern. (If you go read &lt;a href="http://libertyfallsdown.wordpress.com/2013/02/22/villanelle/">Liberty&amp;rsquo;s villanelle&lt;/a> she explains it properly at the start.)&lt;/p>
&lt;p>However, after reading both &lt;a href="http://carolefindsherwings.wordpress.com/2013/02/23/ward-26-a-villanelle/">Carole&amp;rsquo;s&lt;/a> and &lt;a href="http://libertyfallsdown.wordpress.com/2013/02/22/villanelle/">Liberty&amp;rsquo;s&lt;/a>, I was feeling they&amp;rsquo;d both done very depressing poems. It might be a strict structure of poem, but there&amp;rsquo;s no need to make the subject matter so down!&lt;/p>
&lt;p>So here&amp;rsquo;s my overly enthusiastically attempt to try and balance the world of villanelle&amp;rsquo;s into something less depressing!&lt;/p>
&lt;blockquote>
&lt;p>Striding out down the street at last,&lt;br>
Like I own this town,&lt;br>
Tipping my hat to all that I passed.&lt;/p>
&lt;p>Smiling at a friendly chugger who asked,&lt;br>
Grinning at an exuberant clown,&lt;br>
Striding out down the street at last.&lt;/p>
&lt;p>Saluting the bookie behind his glass,&lt;br>
Turning frowns upside down,&lt;br>
Tipping my hat to all that I passed.&lt;/p>
&lt;p>Tapping my feet and having a blast,&lt;br>
Abusing verbs like they were a noun,&lt;br>
Striding out down the street at last.&lt;/p>
&lt;p>Being amused by kids playing on grass,&lt;br>
Seeing the queen in her glorious crown,&lt;br>
Tipping my hat to all that I passed.&lt;/p>
&lt;p>Compared to sadness I am a contrast,&lt;br>
Cheering folk up in my dressing gown,&lt;br>
Striding out down the street at last,&lt;br>
Tipping my hat to all that I passed.&lt;/p>
&lt;/blockquote></description></item><item><title>Pair new device with Nexxus Drive Transmit Pro</title><link>https://caiustheory.com/pair-new-device-with-nexxus-drive-transmit-pro/</link><pubDate>Tue, 12 Feb 2013 18:26:59 +0000</pubDate><guid>https://caiustheory.com/pair-new-device-with-nexxus-drive-transmit-pro/</guid><description>&lt;p>The device is a bluetooth to FM transmitter with Model number NEX-FMTX-BTCK. (Hereafter DTP.)&lt;/p>
&lt;p>The set of instructions I use to pair it to a new device, having lost the user manual/instruction booklet, is as follows:&lt;/p>
&lt;ol>
&lt;li>Remove all previously paired devices from range (turn them off/move them away from the DTP.)&lt;/li>
&lt;li>Turn the power on to the DTP without touching any buttons.&lt;/li>
&lt;li>Let it flash the blue call button a couple of times as it searches for known devices.&lt;/li>
&lt;li>Hold the call button down until the call/hangup buttons flash blue/red respectively.&lt;/li>
&lt;li>Find the &amp;ldquo;Drive Transmit Pro&amp;rdquo; on your device you want paired to it and pair with DTP.&lt;/li>
&lt;li>Test out the pairing by calling your girlfriend and talking to her in a funny accent.&lt;/li>
&lt;li>Celebrate with a beer!&lt;/li>
&lt;/ol></description></item><item><title>Church intertwined with State</title><link>https://caiustheory.com/church-intertwined-with-state/</link><pubDate>Tue, 05 Feb 2013 23:06:18 +0000</pubDate><guid>https://caiustheory.com/church-intertwined-with-state/</guid><description>&lt;p>In the UK currently we&amp;rsquo;re moving (slowly) toward the &lt;a href="http://www.publications.parliament.uk/pa/bills/cbill/2012-2013/0126/cbill_2012-20130126_en_1.htm">same sex marriage bill&lt;/a> making it&amp;rsquo;s way into law. (It&amp;rsquo;s got a way to go still, but support seems to be there now at least.)&lt;/p>
&lt;p>For the record, I&amp;rsquo;m glad to see the state moving toward allowing two people to be united under law, irrespective of terminology used - and with equal rights to those currently enjoyed by the uniting of a man &amp;amp; woman to date. But for a while now I&amp;rsquo;ve been thinking that the discussion is presented in an unclear fashion, which causes people to jump to polarising positions on it, without any common ground.&lt;/p>
&lt;p>The way I see it is the UK has been a country with Religion and State intertwined for many, many hundreds of years - and therefore we have some constructs that exist both in law, and religion, but are conflated under one word and changing one appears to be changing them both.&lt;/p>
&lt;p>The Church of England is Protestant, because Henry VIII wanted to get a divorce and the Catholics wouldn&amp;rsquo;t allow him that, so we as a country &amp;ldquo;forked&amp;rdquo; our own religion that wasn&amp;rsquo;t so different, but allowed divorce of marriage. Times were slightly different back then, the church had a lot more direct power in terms of laws &amp;amp; how people lived. We&amp;rsquo;re a more diverse society today, and the church has less (direct?) involvement in our laws, although older laws are still based upon that original conflation of state and church.&lt;/p>
&lt;p>I almost wonder if in this case (and others) we need to start diverging church from state and allowing the state to change things irrespective of the church, whilst still allowing the church to continue unhindered with practices it&amp;rsquo;s held for many years. Seems like the best of both worlds almost - in law we are a very generic and equal society, and if you wish to belong to or align with a group that has more specific beliefs, then that is open to you as well.&lt;/p>
&lt;p>Lets jump back to gay marriage here as an example then. If we define state marriage to be &amp;ldquo;the unity of two human beings, irrespective of their attributes&amp;rdquo;, then everyone is equal to join with a partner in the eyes of the law, and all such partnerships are afforded the lawful benefits that come with that unity. The church (and indeed, all religions) are also then free to define religious marriage in their doctrine as they wish, so they can say that for them it&amp;rsquo;s only permissible between a man and a woman. And if you wish to join with a partner following that doctrine, then you have to meet their rules.&lt;/p>
&lt;p>In this circumstance, I wonder how much of it is a hangup on the word &amp;ldquo;marriage&amp;rdquo;. I can see how the state wants to keep hold of it to describe partnerships between two people, and also that religions want to keep hold of it as they&amp;rsquo;ve been using it for years and neither wish to yield the word for the other to use. Which possibly means people think solely of this issue as just being an intertwined construct between state and religion, and not as the state giving everyone equality being a separate issue.&lt;/p></description></item><item><title>evil.rb</title><link>https://caiustheory.com/evil-rb/</link><pubDate>Wed, 23 Jan 2013 11:07:43 +0000</pubDate><guid>https://caiustheory.com/evil-rb/</guid><description>&lt;p>Here be hax. Don&amp;rsquo;t &lt;strong>ever&lt;/strong> do these. ;-)&lt;/p>
&lt;h2 id="reduce-local-variables-with-instance_eval">Reduce local variables with instance_eval&lt;/h2>
&lt;p>Sometimes (usually in a one-liner) I want to do some work with a value without assigning it to a variable. Chucking an &lt;code>#instance_eval&lt;/code> call in there will set &lt;code>self&lt;/code> to the value, which saves having to assign it to a local value. Pretty much only used by me in one-off scripts or cli commands.&lt;/p>
&lt;h4 id="good">Good&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">end_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;24 Dec 2011&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;23 Jan 2013&amp;#34;&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="o">|&lt;/span> &lt;span class="no">Date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">start_date&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> to &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">end_date&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> is &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">end_date&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_i&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> days&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="bad">Bad&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">puts&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;24 Dec 2011&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;23 Jan 2013&amp;#34;&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="o">|&lt;/span> &lt;span class="no">Date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">.&lt;/span>&lt;span class="n">instance_eval&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> to &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">last&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> is &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">last&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">first&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_i&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> days&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>See, way less code! &lt;em>cough, cough&lt;/em>&lt;/p>
&lt;h3 id="bonus-usage-misdirection">Bonus usage: Misdirection&lt;/h3>
&lt;p>I also dropped some instance_eval on our campfire bot at &lt;a href="https://emberads.com/">EmberAds&lt;/a> to always blame one person, but without the code reading as such.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%w{Dom Mel Caius CBetta Baz}&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">instance_eval&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;(4V5A8F5T=&amp;amp;$`&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unpack&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;u&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That does not return one of the array elements as you might think it does from quickly scanning the code…&lt;/p>
&lt;h2 id="set-method-local-variables-in-default-arguments">Set method-local variables in default arguments&lt;/h2>
&lt;p>You have a method and it takes one argument, which has a default value of &lt;code>nil&lt;/code> specified. You then run into the situation where you need to know if &lt;code>nil&lt;/code> was passed to the method, or if you&amp;rsquo;re getting the default value of &lt;code>nil&lt;/code>. You could change the default value to something you choose to be the &amp;ldquo;default value&amp;rdquo; and unlikely to be passed from elsewhere as the argument&amp;rsquo;s value, and reset the parameter to &lt;code>nil&lt;/code> after checking it, like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">output&lt;/span> &lt;span class="nb">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="ss">:default_value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">name&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="ss">:default_value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;caius&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kp">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name: &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="nb">name&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">inspect&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -- default: &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">default&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">inspect&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;name: \&amp;#34;caius\&amp;#34; -- default: true&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;fred&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;name: \&amp;#34;fred\&amp;#34; -- default: nil&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s quite a lot of code added to the method just to find out if we passed a default value or not. And if we forget to reset the value when it&amp;rsquo;s &lt;code>:default_value&lt;/code> then we end up leaking that into whatever the method does with that value. We also have the problem that one day the program &lt;em>could&lt;/em> possibly send that &amp;ldquo;default value&amp;rdquo; we&amp;rsquo;ve chosen as the actual parameter, and we&amp;rsquo;d blindly change it thinking it was set as the default value, not the passed argument.&lt;/p>
&lt;p>Instead we could (ab)use the power of ruby, and have ruby decide to set &lt;code>default = true&lt;/code> for us when, and only when, the variable is set &lt;em>to&lt;/em> the default value.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">output&lt;/span> &lt;span class="nb">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kp">true&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="s2">&amp;#34;caius&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name: &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="nb">name&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">inspect&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -- default: &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">default&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">inspect&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;name: \&amp;#34;caius\&amp;#34; -- default: true&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;fred&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;name: \&amp;#34;fred\&amp;#34; -- default: nil&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As you can see, the output is identical. Yet we have no extra code &lt;em>inside&lt;/em> the method to figure out if we were given the default value or not. And as a bonus to that, we no longer have to check for a specific value being passed and presume that is actually the default, and not one passed by the program elsewhere.&lt;/p>
&lt;p>I posted this one in &lt;a href="https://gist.github.com/1528785">a gist&lt;/a> a while back (to show &lt;a href="http://avdi.org/">Avdi&lt;/a> it looks like), and people came up with some more insane things to do with it, including &lt;a href="https://gist.github.com/1528785#comment-71861">returning early&lt;/a>, &lt;a href="https://gist.github.com/1528785#comment-71862">raising errors&lt;/a> or even &lt;a href="https://gist.github.com/1528785#comment-71876">redefining the current method&lt;/a>, all from the argument list! I&amp;rsquo;d suggest going to read them, it&amp;rsquo;s a mixture of OMG HAHA and OMFG NO WAY WHYY?!?!.&lt;/p>
&lt;h3 id="dont-do-this">Don&amp;rsquo;t do this.&lt;/h3>
&lt;p>Don&amp;rsquo;t do the above. No really, don&amp;rsquo;t do them. Unless you&amp;rsquo;re writing a one-off thing. But seriously, don&amp;rsquo;t do them. :-D&lt;/p></description></item><item><title>Some Small Refactorings in Ruby</title><link>https://caiustheory.com/some-small-refactorings-in-ruby/</link><pubDate>Wed, 16 Jan 2013 12:23:54 +0000</pubDate><guid>https://caiustheory.com/some-small-refactorings-in-ruby/</guid><description>&lt;p>Here&amp;rsquo;s a few things I refactor as I write code down initially. Not entirely convinced it&amp;rsquo;s strictly refactoring, but it&amp;rsquo;s how I amend from one pattern I see in a line or three of code into a different structure that I feel achieves the same result with cleaner or more concise code.&lt;/p>
&lt;h3 id="multiple-equality-comparisons">Multiple equality comparisons&lt;/h3>
&lt;p>Testing the equality of an object against another is fairly simple, just do &lt;code>foo == &amp;quot;bar&amp;quot;&lt;/code>. However, I usually try to test against multiple objects in a slightly different way. Your first thought might be that the easiest way is just to chain a series of &lt;code>==&lt;/code> with the OR (&lt;code>||&lt;/code>) operator.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;bar&amp;#34;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;baz&amp;#34;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="ss">:sed&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">5&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I much prefer to flip it around, think of the objects I&amp;rsquo;m testing against as a collection (&lt;code>Array&lt;/code>), and then ask them if they contain the object I&amp;rsquo;m checking. And for that, I use &lt;code>Array#include?&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;bar&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;baz&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:sed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">include?&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">foo&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>(And if you&amp;rsquo;re only testing against strings, you could use &lt;code>%w(bar baz)&lt;/code> as a shortcut to create the array. Here&amp;rsquo;s more &lt;a href="http://caiustheory.com/ruby-shortcuts">ruby shortcuts&lt;/a>.)&lt;/em>&lt;/p>
&lt;h3 id="assigning-multiple-items-from-a-nested-hash-to-variables">Assigning multiple items from a nested hash to variables&lt;/h3>
&lt;p>Occasionally I find myself needing to be given a hash of a hash of data (most recently, an &lt;a href="https://github.com/intridea/omniauth/wiki">omniauth&lt;/a> auth hash) and assign some values from it to separate variables within my code. Given the following hash, containing a nested hash:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">details&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">uid&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;12345&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">info&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Caius Durling&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">nickname&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;caius&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Lets say we want to extract the name and nickname fields from &lt;code>details[:info]&lt;/code> hash into their own local variables (or instance variables within a class, more likely.) We should probably handle the case of &lt;code>details[:info]&lt;/code> not being a hash, and try not to read from it if that&amp;rsquo;s the case - so we might end up with something like the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">details&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:info&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">details&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:info&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="ss">:name&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">nickname&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">details&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:info&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">details&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:info&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="ss">:nickname&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">name&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;Caius Durling&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">nickname&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;caius&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then in the spirit of &lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">DRYing&lt;/a> up our code, we see there&amp;rsquo;s duplication in both lines in checking &lt;code>details[:info]&lt;/code> exists (not actually that it&amp;rsquo;s a hash, but hey ho, we rely on upstream to send us &lt;code>nil&lt;/code> or a hash.) So we reduce it down using an if statement and give ourselves slightly less to type at the same time.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">((&lt;/span> &lt;span class="n">info&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">details&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:info&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">info&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:name&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nickname&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">info&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:nickname&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">name&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;Caius Durling&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">nickname&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;caius&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="returning-two-values-conditionally">Returning two values conditionally&lt;/h3>
&lt;p>Sometimes a method will end with a ternary, where depending on a condition it&amp;rsquo;ll either return one or another value. If this conditional returns true, then the first value is returned. Otherwise it returns the second value. You could quite easily write it out as an if/else longer-form block too.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">my_method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@blah&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">foo&lt;/span> &lt;span class="p">?&lt;/span> &lt;span class="ss">:foo_matches&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="ss">:no_match&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>My brain finds picking the logic in this apart slightly harder mentally, than if I drop a &lt;a href="http://en.wikipedia.org/wiki/Return_early">return early&lt;/a> bomb on the method. Then it reads more akin to how I&amp;rsquo;d think through the logic. Return the first value if this conditional returns true. Otherwise the method returns this second value. I think the second value being on a completely separate line helps me make this mental distinction quicker too.&lt;/p>
&lt;p>So I&amp;rsquo;d write it this way:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">my_method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="ss">:foo_matches&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="vi">@blah&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">foo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:no_match&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="returning-nil-or-a-value-conditionally">Returning nil or a value conditionally&lt;/h3>
&lt;p>Following on from the last snippet, but taking advantage of the ruby runtime a bit more, is when you&amp;rsquo;re wanting to return a value if a conditional is true, or otherwise false. The easy way is to just write &lt;code>nil&lt;/code> in the ternary:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">my_method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="ss">:bar&lt;/span> &lt;span class="p">?&lt;/span> &lt;span class="ss">:foo_matches&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="kp">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>However, we know ruby returns the result of the last expression in the method. And that if a single line conditional isn&amp;rsquo;t met, it returns nil from the expression. Combining that, we can rewrite the previous example into this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">my_method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:foo_matches&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="vi">@foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="ss">:bar&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And it will still return nil in the case that &lt;code>@foo&lt;/code> doesn&amp;rsquo;t match &lt;code>:bar&lt;/code>.&lt;/p>
&lt;h3 id="returning-a-boolean">Returning a boolean&lt;/h3>
&lt;p>Sometimes you have a method that returns the result of a conditional, but it&amp;rsquo;s written to return true/false in a conditional instead.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">my_method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="ss">:bar&lt;/span> &lt;span class="p">?&lt;/span> &lt;span class="kp">true&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="kp">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The really easy refactor here is to just remove the ternary and leave the conditional.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">my_method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@foo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="ss">:bar&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And of course if you were returning &lt;code>false&lt;/code> when the conditional evaluates to &lt;code>true&lt;/code>, you can either negate the comparison (use &lt;code>!=&lt;/code> in that example), or negate the entire conditional result by prepending &lt;code>!&lt;/code> to the line.&lt;/p></description></item><item><title>Why I love DATA</title><link>https://caiustheory.com/why-i-love-data/</link><pubDate>Tue, 08 Jan 2013 19:09:42 +0000</pubDate><guid>https://caiustheory.com/why-i-love-data/</guid><description>&lt;p>In a ruby script, there&amp;rsquo;s a keyword &lt;code>__END__&lt;/code> that for a long time I thought just marked anything after it as a comment. So I used to use it to store snippets and notes about the script that weren&amp;rsquo;t really needed inline. Then one day I stumbled across the &lt;code>DATA&lt;/code> constant, and wondered what flaming magic it was.&lt;/p>
&lt;p>&lt;code>DATA&lt;/code> is in fact an IO object, that you can read from (or anything else you&amp;rsquo;d do with an IO object). It contains all the content after &lt;code>__END__&lt;/code> in that ruby script file&lt;!-- raw HTML omitted -->*&lt;!-- raw HTML omitted -->. (It only exists when the file contains &lt;code>__END__&lt;/code>, and for the first file ruby invokes though. See &lt;!-- raw HTML omitted -->footnote&lt;!-- raw HTML omitted --> for more details.)&lt;/p>
&lt;p>How can we use this, and why indeed do I love this fickle constant? I mostly use it for quick scripts where I need to process text data, rather than piping to STDIN.&lt;/p>
&lt;p>Given a list of URLs that I want to open in my web browser and look at, I could do the following for instance:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="no">DATA&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">each_line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="ss">:chomp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">each&lt;/span> &lt;span class="k">do&lt;/span> &lt;span class="o">|&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sb">`open &amp;#34;&lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">&amp;#34;`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">__END__
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">http://google.com/
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">http://yahoo.com/
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>which upon running (on a mac) would open all the URLs listed in DATA in my default web browser. (For bonus points, use &lt;a href="https://github.com/copiousfreetime/launchy#readme">Launchy&lt;/a> for cross-platform compatibility.) Really handy &amp;amp; quick/simple when you&amp;rsquo;ve got 500+ URLs to open at once to go through. (I once had a job that required me to do this daily. Fun.)&lt;/p>
&lt;p>Or given a bunch of CSV data that you just want one column for, you could reach for &lt;code>cut&lt;/code> or &lt;code>awk&lt;/code> in the terminal, but ruby has a really good CSV library which I trust and know how to use already. Why not just use that &amp;amp; &lt;code>DATA&lt;/code> to pull out the field you want?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">require&lt;/span> &lt;span class="s2">&amp;#34;csv&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">CSV&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="no">DATA&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">headers&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kp">true&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">each&lt;/span> &lt;span class="k">do&lt;/span> &lt;span class="o">|&lt;/span>&lt;span class="n">row&lt;/span>&lt;span class="o">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">puts&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;kName&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">__END__
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">kId,kName,kURL
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">1,Google UK,http://google.co.uk
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">2,&amp;#34;Yahoo, UK&amp;#34;,http://yahoo.co.uk
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; Google UK&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; Yahoo, UK&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I find when the data I want to munge is already in my clipboard, and I can run ruby scripts directly from text editors without having to save a file, it saves having to write the data out to a file, have ruby read it back in, etc just to do something with the data. I can just write the script reading from &lt;code>DATA&lt;/code>, paste the data in and run it. Which also lets me run it iteratively and build up a slightly more complex script that I don&amp;rsquo;t want to keep. Then do what I need with the output and close the file without saving it.&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->*&lt;!-- raw HTML omitted --> technically DATA is an IO handler to read &lt;code>__FILE__&lt;/code>, which has been wound forward to the start of the first line after &lt;code>__END__&lt;/code> in the file. And it only exists for the first ruby file to be invoked by the interpreter.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">cat &amp;gt; tmp/data.rb &lt;span class="s">&amp;lt;&amp;lt;RUBY
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">p DATA.read
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">__END__
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">data.rb
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">RUBY&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ruby tmp/data.rb
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; &amp;#34;data.rb\n&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cat &amp;gt; tmp/data-require.rb &lt;span class="s">&amp;lt;&amp;lt;RUBY
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">require &amp;#34;./tmp/data&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">RUBY&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ruby tmp/data-require.rb
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; /Users/caius/tmp/data.rb:1:in `&amp;lt;top (required)&amp;gt;&amp;#39;: uninitialized constant DATA (NameError)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And because it&amp;rsquo;s a file handle pointing at the current file, you can rewind it and read the entire ruby script into itself…&lt;/p>
&lt;pre>&lt;code>$ ruby tmp/readself.rb
DATA.rewind
print DATA.read
__END__
something goes here
&lt;/code>&lt;/pre></description></item><item><title>Geolocation in nginx</title><link>https://caiustheory.com/geolocation-in-nginx/</link><pubDate>Tue, 04 Dec 2012 09:42:00 +0000</pubDate><guid>https://caiustheory.com/geolocation-in-nginx/</guid><description>&lt;p>Sometimes you need to have a rough idea of where your website visitor is located. There&amp;rsquo;s many ways to geolocate them, but if you just want to go to country level then &lt;a href="http://dev.maxmind.com/geoip/geolite">MaxMind have free geo databases&lt;/a> available to help you. When we needed to do this quickly on-the-fly at EmberAds, we came up with the &lt;a href="https://github.com/emberads/trifle#readme">trifle&lt;/a> gem, which supports ipv4 and ipv6 lookups.&lt;/p>
&lt;p>Recently I was searching for something else to do with nginx and ran across &lt;a href="http://www.ruby-forum.com/topic/125810">a mailing list thread&lt;/a> about using the maxmind database with nginx&amp;rsquo;s &lt;a href="http://wiki.nginx.org/NginxHttpGeoModule">HTTP Geo module&lt;/a> and do the lookup directly in nginx itself. Finally got a chance to sit down and work out the logistics of doing this. I&amp;rsquo;ve done this on an ubuntu 12.04 box, with the expected config file layouts that come with ubuntu.&lt;/p>
&lt;p>Run the following on your server (as someone with write access to nginx config files):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Generate the text file for nginx to import&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">perl &amp;lt;&lt;span class="o">(&lt;/span>curl -s https://raw.github.com/nginx/nginx/master/contrib/geo2nginx.pl&lt;span class="o">)&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&amp;lt; &amp;lt;&lt;span class="o">(&lt;/span>&lt;span class="nv">zip&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>tempfile&lt;span class="k">)&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>curl -so &lt;span class="nv">$zip&lt;/span> http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="o">&amp;amp;&amp;amp;&lt;/span> unzip -p &lt;span class="nv">$zip&lt;/span>&lt;span class="o">)&lt;/span> &amp;gt; /etc/nginx/nginx_ip_country.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Tell nginx to work out the IP country and store in variable&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;geo $IP_COUNTRY {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> default --;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> include /etc/nginx/nginx_ip_country.txt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">}&amp;#39;&lt;/span> &amp;gt; /etc/nginx/conf.d/ip_country.conf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now go find the http block for the vhost you want to have the header passed to, and assuming it&amp;rsquo;s passenger, add the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-nginx" data-lang="nginx">&lt;span class="line">&lt;span class="cl">&lt;span class="k">passenger_set_cgi_param&lt;/span> &lt;span class="s">HTTP_X_IP_COUNTRY&lt;/span> &lt;span class="nv">$IP_COUNTRY&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(If you don&amp;rsquo;t use passenger, look at the docs for &lt;a href="http://wiki.nginx.org/HttpProxyModule#proxy_pass_header">proxy_pass_header&lt;/a> or &lt;a href="http://wiki.nginx.org/HttpFastcgiModule#fastcgi_pass_header">fastcgi_pass_header&lt;/a> to see which you&amp;rsquo;ll require for your setup.)&lt;/p>
&lt;p>Reload nginx, and behold, &lt;code>request.env[&amp;quot;HTTP_X_IP_COUNTRY&amp;quot;]&lt;/code> (assuming a rack app running under ruby) will be a two letter country code, or &lt;code>&amp;quot;--&amp;quot;&lt;/code>.&lt;/p>
&lt;p>Unfortunately this is IPv4 only currently, there&amp;rsquo;s a &lt;a href="http://forum.nginx.org/read.php?29,232648">thread on the nginx mailing list from November 2012&lt;/a> saying IPv6 support should be coming on the v1.3 branch of nginx, but with no known ETA. So currently for IPv6 support, take a look at &lt;a href="https://github.com/emberads/trifle#readme">EmberAds&amp;rsquo; trifle gem&lt;/a> instead.&lt;/p></description></item><item><title>Mounting Harman Kardon Soundsticks on the wall</title><link>https://caiustheory.com/mounting-harman-kardon-soundsticks-on-the-wall/</link><pubDate>Tue, 06 Nov 2012 20:46:45 +0000</pubDate><guid>https://caiustheory.com/mounting-harman-kardon-soundsticks-on-the-wall/</guid><description>&lt;p>Having recently moved my Soundstick III&amp;rsquo;s into the front room, I&amp;rsquo;ve been thinking of a way to wall mount them safely to free up table room. Googling eventually turned up just one person who has previously documented &lt;a href="http://www.thanatopsic.org/hendrik/article/102/hot-hotdesking-action">mounting his soundsticks&lt;/a> on the wall, using 22mm plumbing clips (intended for 22mm central heating pipes).&lt;/p>
&lt;p>A quick scrounge round the local Homebase this afternoon yielded a pack of similar clips, 5x 22mm push clips for £1.99. Having just fitted the speakers to the wall, they&amp;rsquo;re nice and secure (providing no-one hangs on them, which they shouldn&amp;rsquo;t do), fairly neat and simple to fit.&lt;/p>
&lt;p>I&amp;rsquo;ve left the subwoofer on the floor under the table, and only mounted the &amp;ldquo;sticks&amp;rdquo; (tweeters) on the wall, one each side of the mirror over our dining table. I can then conveniently run the cables to the &amp;ldquo;sticks&amp;rdquo; behind the mirror and keep it looking neater.&lt;/p>
&lt;p>I affixed the clips to the wall, one either side of the mirror with enough space for the speaker to sit without overlapping the mirror. Mostly just held the stick up and guessed at where to put the clip, but it looks ok.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Then I bent the speaker stand backwards behind the stick (don&amp;rsquo;t worry, it&amp;rsquo;s on a hinge!) and threaded the cable through the middle of the ring to make it sit flusher against the wall.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>And then it was just a case of easing the speaker ring into the clip, with the clip at the top of the ring (picture below if you can&amp;rsquo;t visualise that easily). I think the rings are more like 24-25mm so it takes a bit of easing to get them in there. Once it&amp;rsquo;s in there&amp;rsquo;s no play in the clip for it to wiggle out though, even though it&amp;rsquo;s plastic. I tried not to fatigue the clip arms too much wiggling it in there as well, so as to minimise the chance of it failing over time. (Something to check periodically!)&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Lastly, I just zip tied the cables together behind the mirror, and ran them down vertically from the middle to the floor and plugged them in. Sounds fantastic, and due to being plugged into an &lt;a href="http://www.apple.com/airportexpress/">Airport Express&lt;/a>, anything compatible can stream audio through them wirelessly. Fabulous darling!&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>&lt;em>(Click any image for a larger version)&lt;/em>&lt;/p></description></item><item><title>Musical Quiz</title><link>https://caiustheory.com/musical-quiz/</link><pubDate>Wed, 10 Oct 2012 14:11:41 +0000</pubDate><guid>https://caiustheory.com/musical-quiz/</guid><description>&lt;p>Using only song titles from ONE ARTIST, cleverly answer these questions. Try not to repeat a song title. It’s harder than you think.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Human Affliction</title><link>https://caiustheory.com/human-affliction/</link><pubDate>Mon, 09 Apr 2012 14:04:32 +0000</pubDate><guid>https://caiustheory.com/human-affliction/</guid><description>&lt;p>That damned human affliction,&lt;br>
Missing someone like an addiction,&lt;br>
The cure&amp;rsquo;s quite simple,&lt;br>
Like bursting a pimple,&lt;br>
Hug them, hold them, repetition.&lt;/p></description></item><item><title>Where did life go?</title><link>https://caiustheory.com/where-did-life-go/</link><pubDate>Fri, 30 Mar 2012 16:33:51 +0000</pubDate><guid>https://caiustheory.com/where-did-life-go/</guid><description>&lt;p>Into the past,&lt;br>
with our regrets and tears,&lt;br>
and our successes and cheers.&lt;/p></description></item><item><title>Install capybara-webkit gem on Ubuntu</title><link>https://caiustheory.com/install-capybara-webkit-gem-on-ubuntu/</link><pubDate>Thu, 01 Mar 2012 11:01:34 +0000</pubDate><guid>https://caiustheory.com/install-capybara-webkit-gem-on-ubuntu/</guid><description>&lt;p>Dear future Caius searching for this issue,&lt;/p>
&lt;p>The apt package you need to install to use the capybara-webkit rubygem on ubuntu (tested on 10.04 and 11.10) is &lt;code>libqt4-dev&lt;/code>. That is, to &lt;code>gem install capybara-webkit&lt;/code>, you need to run &lt;code>aptitude install libqt4-dev&lt;/code>.&lt;/p>
&lt;p>Yours helpfully,&lt;br>
Past Caius&lt;/p></description></item><item><title>Use Readline With Default Ruby on OS X</title><link>https://caiustheory.com/use-readline-with-default-ruby-on-os-x/</link><pubDate>Sun, 05 Feb 2012 18:13:20 +0000</pubDate><guid>https://caiustheory.com/use-readline-with-default-ruby-on-os-x/</guid><description>&lt;p>OS X Lion comes with ruby 1.8.7-p249 installed, although it&amp;rsquo;s compiled against libedit rather than libreadline. Whilst libedit is a mostly-compatible replacement for libreadline, I find there&amp;rsquo;s a couple of settings I&amp;rsquo;m used to that don&amp;rsquo;t work in libedit. (Like &lt;code>history-beginning-search-backward&lt;/code>.)&lt;/p>
&lt;p>Luckily you can grab the source of ruby and compile just the readline extension, and move it into the right place for it to just work. Here&amp;rsquo;s what&amp;rsquo;s been working for me:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Install readline using homebrew&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">brew install readline
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Download the ruby source and check out 1.8.7-p249&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir ~/tmp &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> ~/tmp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone git://github.com/ruby/ruby
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ruby
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout v1_8_7_249
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ext/readline
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ruby extconf.rb --with-readline-dir&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>brew --prefix readline&lt;span class="k">)&lt;/span> --disable-libedit
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">make
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now you should have &lt;code>readline.bundle&lt;/code> in the current directory, and it should be compiled against your homebrew-installed readline library, rather than libedit that comes with the system. We can quickly double-check that by using &lt;code>otool&lt;/code> to check what the binary is linked against.&lt;/p>
&lt;pre>&lt;code>$ otool -L readline.bundle
readline.bundle:
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/libruby.1.dylib (compatibility version 1.8.0, current version 1.8.7)
/usr/local/Cellar/readline/6.2.2/lib/libreadline.6.2.dylib (compatibility version 6.0.0, current version 6.2.0)
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
&lt;/code>&lt;/pre>
&lt;p>And in the output you should see a line listing &amp;ldquo;libreadline&amp;rdquo;, and no lines listing &amp;ldquo;libedit&amp;rdquo;. Which that shows, we&amp;rsquo;ve compiled it properly then. Now the bundle is built we need to move it into the right place so it&amp;rsquo;s loaded when ruby is invoked.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">RL_PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin11.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Back up the original bundle, just in cases&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo mv &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$RL_PATH&lt;/span>&lt;span class="s2">/readline.bundle&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$RL_PATH&lt;/span>&lt;span class="s2">/readline.bundle.libedit&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo mv readline.bundle &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$RL_PATH&lt;/span>&lt;span class="s2">/readline.bundle&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And that&amp;rsquo;s it. You&amp;rsquo;ve got a proper compiled-against-readline installed ruby 1.8.7-p249 on 10.7 now.&lt;/p>
&lt;p>One gotcha I ran into was needing to pass the same arguments to rvm when installing any other version of 1.8.7 on the same machine. Simple enough, just need to remember to do it though.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">CC&lt;/span>&lt;span class="o">=&lt;/span>gcc-4.2 rvm install 1.8.7-p357 -C --with-readline-dir&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>brew --prefix readline&lt;span class="k">)&lt;/span> --disable-libedit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>End Of An Era</title><link>https://caiustheory.com/end-of-an-era/</link><pubDate>Thu, 12 Jan 2012 15:30:00 +0000</pubDate><guid>https://caiustheory.com/end-of-an-era/</guid><description>&lt;p>I remember watching &lt;a href="http://www.youtube.com/watch?v=UF8uR6Z6KLc">Steve Jobs&amp;rsquo; commencement speech&lt;/a> for the first time and being fairly touched by the three stories he told in it. The major one that resonated with me at the time, and has since made more sense to me, is the first story he tells about joining the dots later on when you&amp;rsquo;re looking backwards. To quote from it:&lt;/p>
&lt;blockquote>
&lt;p>Of course, it was impossible to connect the dots looking forward when I was in college. But it was very very clear looking backwards ten years later. Again, you can&amp;rsquo;t connect the dots looking forward, you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future.&lt;/p>
&lt;/blockquote>
&lt;p>It made me think back to a time when I was a teenager and someone far older and wiser than me told me one way to think about the future and how what we do today affects where we end up. He described it as holding a piece of string in your hand, with the other end dangling free. The end of the string not attached to you is the future, and where you&amp;rsquo;re holding it is the present. As you do things in life your hand moves around, flicking the string around and amplifying the movements of the present in the future.&lt;/p>
&lt;p>I think what he was trying to impart by telling me that story was to be careful not to do anything too extravagant in the present (like get expelled from school for instance), so as not to affect the future too much. Which I never really took on board at the time, but now I look back at the dots of my (some would say) rather short life so far, and connect them to see how some things influenced other things and how everything works out in the end. But that sometimes you need to push yourself or do something unexpected to get there.&lt;/p>
&lt;h3 id="looking-backwards-to-go-forward">Looking Backwards to go Forward&lt;/h3>
&lt;p>When I look back over the last few years of my life, I find the dots quite amazing to connect. First there was BarCamp Sheffield 2007 where I met &lt;a href="http://www.thehodge.co.uk/">Dom&lt;/a>, and there was Twitter and BarCamp Manchester &amp;amp; Leeds where I met geeks like &lt;a href="http://www.3hv.co.uk/">Rahoul&lt;/a>, &lt;a href="http://johnleach.co.uk/">John&lt;/a> and &lt;a href="http://brightbox.co.uk/">Jeremy&lt;/a> both online and offline. And then in June 2008 I moved to Leeds, sharing a house with Dom and quite quickly ended up being hired into what was basically my dream first job at &lt;a href="http://www.brightbox.com/">Brightbox&lt;/a>.&lt;/p>
&lt;p>And that&amp;rsquo;s where I&amp;rsquo;ve been working for the last 1198 days, having far too much fun, solving weird, wonderful and sometimes downright frustrating problems, all with fantastically awesome and hilarious colleagues. And working on a massive variety of things, from &lt;a href="https://github.com/brightbox/rujitsu/">tiny utilities&lt;/a> to the newly launched &lt;a href="http://www.brightbox.com/">Cloud Platform&lt;/a>.&lt;/p>
&lt;p>And today I flick my wrist ever so slightly more than normal by leaving Brightbox, without really knowing where the future end of the string will eventually end up, but knowing that I&amp;rsquo;ll look back in a few years and see dots connected that I can&amp;rsquo;t imagine today. I truly don&amp;rsquo;t think I could have had a better job to start off as a professional geek, and especially want to thank &lt;a href="http://johnleach.co.uk/">John&lt;/a> and &lt;a href="http://brightbox.co.uk/">Jeremy&lt;/a> for hiring me and helping me start my career in the best way possible.&lt;/p>
&lt;p>As for my next challenge, I&amp;rsquo;m solving interesting problems in the online advertising world with &lt;a href="http://cristianobetta.com/">Cristiano&lt;/a>, &lt;a href="http://www.thehodge.co.uk/">Dom&lt;/a>, &lt;a href="http://missgeeky.com/">Melinda&lt;/a> and &lt;a href="http://www.3hv.co.uk/">Rahoul&lt;/a>. And we&amp;rsquo;re bloody amazing together. :-)&lt;/p></description></item><item><title>Nighttime Horrors</title><link>https://caiustheory.com/nighttime-horrors/</link><pubDate>Tue, 10 Jan 2012 10:51:03 +0000</pubDate><guid>https://caiustheory.com/nighttime-horrors/</guid><description>&lt;blockquote>
&lt;p>Screaming ghouls and scary monsters,&lt;br>
Permeating our subconscious,&lt;br>
At night they roam freely through our dreams,&lt;br>
With the sole intent of causing our screams,&lt;br>
Scaring us until we awake,&lt;br>
Annoyingly, for we know they are fake.&lt;/p>
&lt;/blockquote></description></item><item><title>Defining Ruby Superclasses On The Fly</title><link>https://caiustheory.com/defining-ruby-superclasses-on-the-fly/</link><pubDate>Sun, 18 Dec 2011 01:13:14 +0000</pubDate><guid>https://caiustheory.com/defining-ruby-superclasses-on-the-fly/</guid><description>&lt;p>Any rubyist that&amp;rsquo;s defined a class should understand the following class definition:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Foo&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="no">Object&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It creates a new Constant (&lt;code>Foo&lt;/code>) that is a subclass of &lt;code>Object&lt;/code>. Pretty straightforward. But what you might not know is that ruby executes each line it reads in as it reads them. So we could do the following to show that:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Foo&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="no">Object&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;we just defined object!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And get the following output when we run that file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; we just defined object!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So.. we know ruby is executing things on the fly whilst defining classes for us. How can we use this for profit and shenanigans?! (Err, use this for vanquishing evil and creating readable code I mean. Honest.)&lt;/p>
&lt;p>How about if we&amp;rsquo;ve got a couple of opinionated people who like to think they&amp;rsquo;ve got the biggest ego in the interpreter? The last one to be loaded likes to have any new people ushered into the interpreter to be a subclass of themselves. Lets abuse a global for storing it in, and use a method to choose that on the fly when creating a new class.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">current_awkward_bugger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vg">$awkward_bugger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Simon&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="vg">$awkward_bugger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Simon&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Fred&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">current_awkward_bugger&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">Fred&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">superclass&lt;/span> &lt;span class="c1"># =&amp;gt; Simon&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Harold&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="vg">$awkward_bugger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Harold&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">John&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">current_awkward_bugger&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">John&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">superclass&lt;/span> &lt;span class="c1"># =&amp;gt; Harold&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">Fred&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">superclass&lt;/span> &lt;span class="c1"># =&amp;gt; Simon&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Okay, so that looks a bit different to normally defined classes. We create &lt;code>Simon&lt;/code>, assign him to the awkward bugger global then create &lt;code>Fred&lt;/code>, who subclasses the return value of the &lt;code>current_awkward_bugger&lt;/code> method which happens to be &lt;code>Simon&lt;/code> currently. Then &lt;code>Harold&lt;/code> muscles his way into the interpreter and decides he&amp;rsquo;s going to be the current awkward bugger, so poor &lt;code>John&lt;/code> gets to subclass &lt;code>Harold&lt;/code> even though he&amp;rsquo;s defined in the same way as &lt;code>Fred&lt;/code>. (And as you can see on the last line, Fred&amp;rsquo;s superclass is unchanged even though we changed the &lt;code>awkward_bugger&lt;/code> global.)&lt;/p>
&lt;p>On a somewhat related note there&amp;rsquo;s a lovely method called &lt;code>const_missing&lt;/code> that gets invoked when you call a Constant in ruby that isn&amp;rsquo;t defined. (Much like &lt;code>method_missing&lt;/code> if you&amp;rsquo;re familiar with that.) Means you can do even more shenanigans with non-existent superclasses for classes you&amp;rsquo;re defining.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Simon&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Harold&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Object&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nc">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nf">const_missing&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">konstant&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">[&lt;/span>&lt;span class="no">Simon&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="no">Harold&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">shuffle&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Fred&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="no">ArrogantBastard&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">Fred&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">superclass&lt;/span> &lt;span class="c1"># =&amp;gt; Simon&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Albert&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="no">ArrogantBastard&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">Albert&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">superclass&lt;/span> &lt;span class="c1"># =&amp;gt; Harold&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So here we&amp;rsquo;re choosing from Simon and Harold on the fly each time a missing constant is referenced (in this case the aptly named &lt;code>ArrogantBastard&lt;/code> constant.) If you run this code yourself you&amp;rsquo;ll see the superclasses change on each run according to what your computer picks that time.&lt;/p></description></item><item><title>Magic Bubble</title><link>https://caiustheory.com/magic-bubble/</link><pubDate>Tue, 06 Dec 2011 22:03:46 +0000</pubDate><guid>https://caiustheory.com/magic-bubble/</guid><description>&lt;blockquote>
&lt;p>You and me,&lt;br>
Quietly,&lt;br>
Watching the rain in the stars,&lt;br>
From a bubble near Mars.&lt;/p>
&lt;/blockquote></description></item><item><title>Experimental Procrastination</title><link>https://caiustheory.com/experimental-procrastination/</link><pubDate>Mon, 07 Nov 2011 00:41:49 +0000</pubDate><guid>https://caiustheory.com/experimental-procrastination/</guid><description>&lt;p>A while ago I read a blog post that Elizabeth N wrote, on the &lt;a href="http://naramore.net/blog/the-value-of-self-serving-code">value of writing self-serving code&lt;/a>. Ever since I&amp;rsquo;ve been moderately aware of when I&amp;rsquo;ve written self-serving code, usually either at hackdays, or just little projects where I&amp;rsquo;m either experimenting with something or just bashing out a new idea.&lt;/p>
&lt;p>In fact, I even wrote about one of my recent &amp;ldquo;self-serving&amp;rdquo; projects I bashed out in an evening, &lt;a href="http://caiustheory.com/tweetsavr">TweetSavr&lt;/a>. It has no tests, was written moderately quickly and not refactored immensely (here&amp;rsquo;s hoping the git history backs me up on that! I certainly didn&amp;rsquo;t knowingly majorly refactor it at any point at least.) But it &amp;ldquo;scratched an itch&amp;rdquo; and solved the problem I had, and it works for the limited use case I need it to, so it&amp;rsquo;s a success as far as I&amp;rsquo;m concerned.&lt;/p>
&lt;p>More recently a friend remarked to me in a private conversation that everyone needs to procrastinate occasionally, to save them going &amp;ldquo;stir crazy&amp;rdquo;. Whilst I agree with what she said, everyone needs to switch gears and do something that perhaps you shouldn&amp;rsquo;t, or that won&amp;rsquo;t directly contribute to completing your current task, I couldn&amp;rsquo;t help but draw a link between procrastinating and writing self-serving code.&lt;/p>
&lt;p>Now I&amp;rsquo;m a programmer, it&amp;rsquo;s what I did for a hobby through school, it&amp;rsquo;s what I leapt into a career doing when I was offered the chance and even when I&amp;rsquo;ve had a particularly exhausting week, it&amp;rsquo;s something I&amp;rsquo;ll eventually turn back to. But I realised that often when I procrastinate, I do so by writing self-serving code. My creative output or process if you will is to create things digitally on the computer, be that a web app, hacky script to let me do something I&amp;rsquo;m not supposed to be able to with someone else&amp;rsquo;s application, just dicking around or exploring whatever tidbit of interesting info/behaviour in a language or library someone&amp;rsquo;s just shared on IRC.&lt;/p>
&lt;p>&lt;em>Aside: I&amp;rsquo;ve often joked (semi-seriously) that if/when I have enough cash in the bank to not have to actually have a &amp;ldquo;day job&amp;rdquo;, I&amp;rsquo;ll just spend all day building the random ideas that get tossed out on IRC instead. Quite often the smaller things I code up anyway already of an evening and they end up in my &lt;a href="https://gist.github.com/caius">gists&lt;/a>.&lt;/em>&lt;/p>
&lt;p>Now it&amp;rsquo;s unhealthy and counter-productive to want to program 24/7, at least in the long term. (Doing the odd 24 hour hackday event here and there can mean winning fun prizes to play with however.) And sometimes all that you need to do to solve a problem you&amp;rsquo;ve been butting your head against for the last couple of hours is to get off the damn computer. (I usually find taking a shower makes my subconscious reveal the answer it&amp;rsquo;s been quietly computing and hey presto, I know how to solve the problem properly!) At other times it just requires changing gears and flexing a different part of your brain muscle. Like say, writing self-serving code. And procrastinating by doing so.&lt;/p>
&lt;p>I&amp;rsquo;m not entirely sure what the point of this thought process is, or if there can really be a point to it, but it really intrigued me drawing a link between procrastinating and writing self-serving code. I can imagine other creatively minded people might do much the same thing, an artist just sketching for the sake of sketching, or a writer taking a couple of hours off from her next novel to write a short story for her blog. (That last one is actually something a friend&amp;rsquo;s done, go read her &lt;a href="http://libertyfallsdown.wordpress.com/tag/short-story/">short stories&lt;/a>, they&amp;rsquo;re quite good. Start from the bottom though.)&lt;/p>
&lt;p>And of course sometimes you just need to vegetate and read facebook (or twitter), but constructive procrastination does serve a real purpose I think, and can be quite useful as well.&lt;/p></description></item><item><title>Install GCC-4.2.1 (Apple build 5666.3) with Xcode 4.2</title><link>https://caiustheory.com/install-gcc-421-apple-build-56663-with-xcode-42/</link><pubDate>Sun, 30 Oct 2011 17:36:48 +0000</pubDate><guid>https://caiustheory.com/install-gcc-421-apple-build-56663-with-xcode-42/</guid><description>&lt;p>As of Xcode 4.2 Apple have stopped bundling GCC with it, shipping only the (mostly) compatible llvm-gcc binary instead. The suggested fix is to install GCC using the &lt;a href="https://github.com/kennethreitz/osx-gcc-installer">osx-gcc-installer&lt;/a> project. However, I wanted to build and install it from source, which apple provides at &lt;a href="http://opensource.apple.com/">http://opensource.apple.com/&lt;/a>.&lt;/p>
&lt;p>You should already have installed Xcode 4.2 from the app store, then basically the following steps are to grab the tarball from the &lt;a href="http://opensource.apple.com/release/developer-tools-41/">4.1 developer tools source&lt;/a>, unpack &amp;amp; compile it, then install it into the right places.&lt;/p>
&lt;p>&lt;strong>Update 2016-07-03:&lt;/strong> I&amp;rsquo;d suggest just using homebrew to install this these days:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">brew install homebrew/dupes/apple-gcc42
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="instructions">Instructions&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Grab and unpack the tarball&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir ~/tmp &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> ~/tmp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">curl -O http://opensource.apple.com/tarballs/gcc/gcc-5666.3.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">tar zxf gcc-5666.3.tar.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> gcc-5666.3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Setup some stuff it requires&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir -p build/obj build/dst build/sym
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># And then build it. You should go make a cup of tea or five whilst this runs.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gnumake install &lt;span class="nv">RC_OS&lt;/span>&lt;span class="o">=&lt;/span>macos &lt;span class="nv">RC_ARCHS&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;i386 x86_64&amp;#39;&lt;/span> &lt;span class="nv">TARGETS&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;i386 x86_64&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">SRCROOT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="nb">pwd&lt;/span>&lt;span class="sb">`&lt;/span> &lt;span class="nv">OBJROOT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="nb">pwd&lt;/span>&lt;span class="sb">`&lt;/span>/build/obj &lt;span class="nv">DSTROOT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="nb">pwd&lt;/span>&lt;span class="sb">`&lt;/span>/build/dst &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nv">SYMROOT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="nb">pwd&lt;/span>&lt;span class="sb">`&lt;/span>/build/sym
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># And finally install it&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo ditto build/dst /
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And now you should have &lt;code>gcc-4.2&lt;/code> in your &lt;code>$PATH&lt;/code>, available to build all the things that &lt;code>llvm-gcc&lt;/code> fails to compile.&lt;/p></description></item><item><title>TweetSavr</title><link>https://caiustheory.com/tweetsavr/</link><pubDate>Sat, 22 Oct 2011 12:05:39 +0000</pubDate><guid>https://caiustheory.com/tweetsavr/</guid><description>&lt;p>I&amp;rsquo;ve had a dream for a while. A simple webapp that takes the last tweet in a conversation and outputs that conversation in chronological order on a page you can link to forevermore. Occasionally I&amp;rsquo;ll google to see if anything new&amp;rsquo;s turned up, but they all seem to do far more, require the start and end tweets or are covered in ads.&lt;/p>
&lt;p>So one friday evening I just built it. It&amp;rsquo;s called &lt;a href="http://tweetsavr.com/">TweetSavr&lt;/a>. It&amp;rsquo;s very simple—to the point the error page is just a standard 500 server error page currently. It fetches, caches and displays a conversation, given just the last tweet in said conversation.&lt;/p>
&lt;p>KISS extends to the interface as well, I&amp;rsquo;m quite a fan of &lt;a href="http://jerz.setonhill.edu/writing/etext/url-hacking.htm">URL hacking&lt;/a> to use webapps, so TweetSavr works on that basis as well. The homepage sort of has some help telling you how to use it, but you basically take the (old-twitter) URL of the last tweet and paste it after tweetsavr.com in the address bar. Eg, &lt;a href="http://tweetsavr.com/http://twitter.com/ElizabethN/status/19766711653765120">http://tweetsavr.com/http://twitter.com/ElizabethN/status/19766711653765120&lt;/a>. It&amp;rsquo;ll then redirect you through to the actual page for that conversation. You can also put just the status id on the end of the URL, &lt;a href="http://tweetsavr.com/19766711653765120">http://tweetsavr.com/19766711653765120&lt;/a> and hey presto, it loads.&lt;/p>
&lt;p>The caching layer is moderately rudimentary, after fetching a tweet that isn&amp;rsquo;t in the cache it writes out a hash of data for that tweet into a yaml file. And when looking up a tweet it checks to see if that file exists, reading it in from disk if it is. Bonus side-effect is it builds up a corpus of tweets as yaml files on disk.&lt;/p>
&lt;p>It lives on the internet at &lt;a href="http://tweetsavr.com/">http://tweetsavr.com/&lt;/a> and the source is on github at &lt;a href="http://github.com/caius/tweetsavr">http://github.com/caius/tweetsavr&lt;/a>&lt;/p>
&lt;p>Side note: isn&amp;rsquo;t it wonderful what we can create given just a few hours, a server somewhere in the cloud, and an idea? Never ceases to amaze me what can be built in just a short amount of time, even the dead simple things.&lt;/p></description></item><item><title>#to_param and keyword slugs</title><link>https://caiustheory.com/to_param-and-keyword-slugs/</link><pubDate>Tue, 05 Jul 2011 23:13:43 +0000</pubDate><guid>https://caiustheory.com/to_param-and-keyword-slugs/</guid><description>&lt;p>Imagine you&amp;rsquo;ve got a blogging app and it&amp;rsquo;s currently generating URL paths like &lt;code>posts/10&lt;/code> for individual posts. You decide the path should contain the post title (in some form) to make your URLs friendlier when someone reads them. I know I certainly prefer to read &lt;a href="http://caiustheory.com/abusing-ruby-19-and-json-for-fun">http://caiustheory.com/abusing-ruby-19-and-json-for-fun&lt;/a> vs &lt;a href="http://caiustheory.com/?id=70">http://caiustheory.com/?id=70&lt;/a>. &lt;em>(That&amp;rsquo;s a fun blog post if you&amp;rsquo;re into (ab)using ruby occasionally!)&lt;/em>&lt;/p>
&lt;p>Now you know &lt;em>all&lt;/em> about how to change the URL path that rails generates—just define &lt;code>to_param&lt;/code> in your app. Something simple that generates a slug consisting of hyphens and lowercase alphanumerical characters. For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 70-abusing-ruby-1-9-json-for-fun&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">to_param&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="nb">id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">-&lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gsub&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/\W/&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;-&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">squeeze&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;-&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">downcase&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>&lt;strong>NB&lt;/strong>: You might want to go the route of storing the slug against the post record in the database and thus generating it before saving the record. In which case the rest of this post is sort of moot and you just need to search on that column. If not, then read on!&lt;/em>&lt;/p>
&lt;p>Now we&amp;rsquo;re generating a nice human-readable URL we need to change the way we find the post in the controller&amp;rsquo;s show action. Up until now it&amp;rsquo;s been a simple &lt;code>@post = Post.find(params[:id])&lt;/code> to grab the record out the database. Problem now is &lt;code>params[:id]&lt;/code> is &lt;code>&amp;quot;70-abusing-ruby-1-9-json-for-fun&amp;quot;&lt;/code>, rather than just &lt;code>&amp;quot;70&amp;quot;&lt;/code>. A quick check in the &lt;a href="http://ruby-doc.org/core/classes/String.html#M001149">String#to_i&lt;/a> docs reveals it &amp;ldquo;Returns the result of interpreting leading characters in str as an integer base base (between 2 and 36).&amp;rdquo; Basically it extracts the first number it comes across and returns it.&lt;/p>
&lt;p>Knowing that we can just lean on it to extract the id before using find to look for the post: &lt;code>@post = Post.find(params[:id].to_i)&lt;/code>. Fantastic! We&amp;rsquo;ve got nice human readable paths on our blog posts and they can be found in the database. All finished… or are we?&lt;/p>
&lt;p>There&amp;rsquo;s still a rather embarassing bug in our code where we&amp;rsquo;re not explicitly checking the slug in the URL against the slug of the Post we&amp;rsquo;ve extracted from the database. If we visited &lt;code>/posts/70-ruby-19-sucks-and-python-rules-4eva&lt;/code> it would load the blog post and render it without batting an eyelid. This has caused &lt;a href="http://www.niemanlab.org/2011/04/how-url-spoofing-can-put-libelous-words-into-news-orgs-mouths/">rather a few embarrassing situations&lt;/a> for some high profile media outlets who don&amp;rsquo;t (or didn&amp;rsquo;t) check their URLs and just output the content. Luckily there&amp;rsquo;s a simple way for us to check this.&lt;/p>
&lt;p>All we want to do is render the content if the id param matches the slug of the post exactly, and return a 404 page if it doesn&amp;rsquo;t. We already know the id param (&lt;code>params[:id]&lt;/code>) and have pulled the Post object out of the database and stored it in an instance variable (&lt;code>@post&lt;/code>). The &lt;code>@post&lt;/code> knows how to generate it&amp;rsquo;s own slug, using &lt;code>#to_param&lt;/code>.&lt;/p>
&lt;p>So we end up with something like the following in our posts controller, which does all the above and correctly returns a 404 if someone enters an invalid slug (even if it starts with a valid post id):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">show&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@post&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">to_i&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render_404&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="k">unless&lt;/span> &lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="vi">@post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_param&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">render_404&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render&lt;/span> &lt;span class="ss">:file&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="no">Rails&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">root&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s2">&amp;#34;public/404.html&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:status&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="ss">:not_found&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And going to an invalid path like &lt;code>/posts/70-ruby-19-sucks-and-python-rules-4eva&lt;/code> just renders the default rails 404 page with a 404 HTTP status. (If you want the id to appear at the end of the path, alter &lt;code>to_param&lt;/code> accordingly and do something like &lt;code>params[:id].match(/\d+$/)&lt;/code> to extract the Post&amp;rsquo;s id to search on.)&lt;/p>
&lt;p>Hey presto, we&amp;rsquo;ve implemented human readable slugs that are tamper-proof (without storing them in the database.)&lt;/p>
&lt;p>&lt;em>(And bonus points if in fact you spotted I used my blog as an example, but that it isn&amp;rsquo;t a rails app. (Nor contains the blog post ID in the pretty URL.) It&amp;rsquo;s actually powered by &lt;a href="http://habariproject.org/">Habari&lt;/a> at the time of posting!&lt;/em>&lt;/p></description></item><item><title>Bad Recruiters - Rhys Evans at Devonshire</title><link>https://caiustheory.com/bad-recruiters-rhys-evans-at-devonshire/</link><pubDate>Wed, 09 Feb 2011 14:03:49 +0000</pubDate><guid>https://caiustheory.com/bad-recruiters-rhys-evans-at-devonshire/</guid><description>&lt;p>This is a linked-in invitation I received from Rhys, and my reply.&lt;/p>
&lt;hr>
&lt;p>&lt;strong>Update 2011-02-10:&lt;/strong> As much as recruiters can be scummy twats, Rhys appears to at least care somewhat about his relationship with potential clients/contacts and has &lt;a href="http://caiustheory.com/bad-recruiters-rhys-evans-at-devonshire#comment-34098">responded in the comments&lt;/a>. Normally my policy with recruiters is a two strike one, first email gets a polite &amp;ldquo;No thanks, go away.&amp;rdquo;, second gets a mini-rant to bugger off and stop contacting me. Rhys hadn&amp;rsquo;t technically contacted me before, but the unsolicited xmas email showed up when I searched my mailbox (which had annoyed me back when I received it.) And asking amongst my peers around at the time showed he was fairly disliked. (As you can see in some of the comments left below as well.) Since then, including a comment left below, a few people I trust have noted he&amp;rsquo;s really not that bad as recruiters go, and the fact he&amp;rsquo;s left a comment acknowledging perhaps his approach is a little misguided is enough for me to see he does still care about trying to be better than the rest of the recruitment crowd.&lt;/p>
&lt;p>I still stand by my initial reply to him, and all other recruiters who don&amp;rsquo;t understand &amp;ldquo;No.&amp;rdquo; however.&lt;/p>
&lt;hr>
&lt;p>On 02/09/11 5:30 AM, Rhys Evans wrote:&lt;/p>
&lt;blockquote>
&lt;p>Hi Caius,&lt;/p>
&lt;p>Good afternoon, I hope all is well.&lt;/p>
&lt;p>I&amp;rsquo;ve noticed we are connected to a number of the same people within the Rails space on LinkedIn. I&amp;rsquo;ve tried you on 07960 268100 to no avail so I&amp;rsquo;d like to add you to my network and make contact.&lt;/p>
&lt;/blockquote>
&lt;p>Hi Rhys,&lt;/p>
&lt;p>I&amp;rsquo;ve already got you blocked on twitter, so we&amp;rsquo;ve obviously run across each other in the past. You also appear to have sent me a Merry Xmas email from Devonshire, with no previous contact initiated by me. (I seem to remember a lot of my friends got those emails as well and we eventually worked out you&amp;rsquo;d scraped Github for them.)&lt;/p>
&lt;p>Now it would appear you&amp;rsquo;re being more intrusive and hunting folk out on linked in, ignoring the fact that they are employed and have specifically set linked in to say they aren&amp;rsquo;t looking for new jobs currently. From asking around you harass a few of my friends, to the point of ringing one up recently to tell them you knew they&amp;rsquo;d changed jobs and where they were now working. If you&amp;rsquo;re going to spend time doing that much research then why not have the decency to not be a completely mannerless cunt and leave them alone when they request you to.&lt;/p>
&lt;p>It would also appear you&amp;rsquo;ve just blanket-spammed me and a few people in my peer group through linked in with the same request, again a pretty dumb thing to do. It&amp;rsquo;s as if you recruiters think we never talk to each other, and don&amp;rsquo;t realise how much you lot being a bunch of pestering spammy bastards taints developers against ever dealing with a recruiter.&lt;/p>
&lt;p>So no, I don&amp;rsquo;t think I do want to accept your invitation to connect. And please never phone, email or contact me via any other means. I&amp;rsquo;m happily employed and if I &lt;em>ever&lt;/em> need the services of a recruiter I&amp;rsquo;ll find someone who actually possesses an ounce of politeness about approaching (potential) candidates.&lt;/p>
&lt;p>Thanks,&lt;br>
Caius&lt;/p></description></item><item><title>Abusing Ruby 1.9 &amp; JSON for fun</title><link>https://caiustheory.com/abusing-ruby-19-and-json-for-fun/</link><pubDate>Mon, 07 Feb 2011 19:16:58 +0000</pubDate><guid>https://caiustheory.com/abusing-ruby-19-and-json-for-fun/</guid><description>&lt;p>Ever since I found out about the new hash syntax you can use in ruby 1.9, and how similar that syntax is to JSON, I&amp;rsquo;ve been waiting for someone to realise you can just abuse &lt;code>eval()&lt;/code> for parsing (some) JSON now.&lt;/p>
&lt;p>For example, lets say we have the following ruby hash, which could be generated by a RESTful api:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">thing&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:person&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:name&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="s2">&amp;#34;caius&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If we pull in the JSON gem and dump that out as a string, we get the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">jsonstr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">thing&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; &amp;#39;{&amp;#34;person&amp;#34;:{&amp;#34;name&amp;#34;:&amp;#34;caius&amp;#34;}}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s… not quite what we wanted. It&amp;rsquo;s not going to turn back into valid ruby as it is. Luckily javascript will parse objects without requiring the attributes to be wrapped in quotes, eg: &lt;code>{some: &amp;quot;attribute&amp;quot;}&lt;/code>. We could build a JSON emitter that does it properly, or we could just run it through a regular expression instead. &lt;em>(Lets also add a space after the colon to aid readability.)&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">jsonstr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gsub!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/&amp;#34;([^&amp;#34;]+)&amp;#34;: /&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;\1: &amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; &amp;#39;{person: {name: &amp;#34;caius&amp;#34;}}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Okay, so now we&amp;rsquo;ve turned a ruby hash into a JSON hash, that can still be parsed by the browser. Here&amp;rsquo;s a screenshot to prove that:&lt;/p>
&lt;p>&lt;img src="http://farm6.static.flickr.com/5300/5425314597_43be5824cf_o.jpg" alt="Valid JSON &amp;rsquo;thing&amp;rsquo;">&lt;/p>
&lt;p>As you can see, it parses that into a valid JS object, complete with person and then (nested) name attributes. If we wanted to, &lt;code>thing[&amp;quot;person&amp;quot;][&amp;quot;name&amp;quot;]&lt;/code> or &lt;code>thing.person.name&lt;/code> would access the nested value &amp;ldquo;caius&amp;rdquo; just fine.&lt;/p>
&lt;p>Now then, we&amp;rsquo;ve proved that is successfully parsed into javascript objects by the browser, generated from a ruby hash. No great shakes there, that&amp;rsquo;s fairly simple and has worked for ages. Now for my next trick, I&amp;rsquo;m going to turn that string of JSON back into a ruby hash, all without going anywhere near the JSON gem.&lt;/p>
&lt;p>Some of you might have guessed what I&amp;rsquo;m about to do and have started hoping you&amp;rsquo;ve guessed wrongly — just for the record I don&amp;rsquo;t condone doing this except for fun and games. The JSON gem is there for a reason ;) With that little disclaimer out the way, here we go!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">thing2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">eval&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">jsonstr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; {:person=&amp;gt;{:name=&amp;gt;&amp;#34;caius&amp;#34;}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">thing2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">thing&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Oh snap! We just turned javascript objects back into valid ruby objects, in one simple method call. And we&amp;rsquo;d be able to access the &amp;ldquo;caius&amp;rdquo; value by calling &lt;code>thing2[:person][:name]&lt;/code>, or creating OpenStructs from the hashes and calling &lt;code>thing2.person.name&lt;/code>. Which is uncannily like the JS!&lt;/p>
&lt;p>&lt;strong>Updated 2011-02-07&lt;/strong>: &lt;a href="http://jens.ayton.se/">Jens Ayton&lt;/a> pointed out unquoted keys aren&amp;rsquo;t strictly valid JSON, which is correct. Amended to say they&amp;rsquo;re parsed as javascript objects instead, with no mention of it being valid JSON.&lt;/p></description></item><item><title>App Store Hidden Preferences</title><link>https://caiustheory.com/app-store-hidden-preferences/</link><pubDate>Thu, 06 Jan 2011 19:45:49 +0000</pubDate><guid>https://caiustheory.com/app-store-hidden-preferences/</guid><description>&lt;p>&lt;em>See the Update at the end before you get excited :(&lt;/em>&lt;/p>
&lt;p>Having just installed 10.6.6 to use the Mac App Store, I was &lt;a href="http://twitter.com/Caius/status/23096911170899968">slightly annoyed&lt;/a> that it fills my dock with apps as I install them. I&amp;rsquo;m a bit strange, in that I use a hidden preference to make the dock uneditable (it stops me accidentally dragging an app off.) But that means I can&amp;rsquo;t drag off the Mac App Store installed apps either.&lt;/p>
&lt;p>Had a quick look through &lt;code>/Applications/App Store.app/Contents/MacOS/App Store&lt;/code> with &lt;code>strings&lt;/code> (love that tool) and noted a few strings that looked interesting. (There&amp;rsquo;s a full list &lt;a href="https://gist.github.com/768442">in this gist&lt;/a>.) There wasn&amp;rsquo;t anything that explicitly stated it stopped it putting anything in the dock, but I did notice an option that stopped it showing &lt;strong>install progress&lt;/strong> in the dock.&lt;/p>
&lt;p>Yank up a terminal window, bash out the following&amp;hellip;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">defaults write com.apple.appstore FRDebugShowInstallProgress -bool NO
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip;head back to the MAS and install another (free) app, and hey presto, it&amp;rsquo;s leaving my dock alone! Hopefully that&amp;rsquo;s all I needed to continue using my Dock as I like. (Hidden, and left alone.)&lt;/p>
&lt;p>&lt;strong>Update 2011-01-06:&lt;/strong>&lt;/p>
&lt;p>Seems my joy was short-lived. I&amp;rsquo;d re-downloaded an app I&amp;rsquo;d already purchased and it just showed download progress in the MAS app, not in the dock. Installing new applications still shows up in the dock (annoyingly.)&lt;/p>
&lt;p>I&amp;rsquo;ve been having a poke through how it all hangs together, and if it&amp;rsquo;s possible to actually block downloads from the Dock or not. It doesn&amp;rsquo;t look like there&amp;rsquo;s a hidden preference to hide new apps from downloading in the dock, you can just disable the progress bars in the dock with prefs. The MAS.app seems to be codenamed &amp;ldquo;Firenze&amp;rdquo;, with &lt;a href="https://gist.github.com/768829">the &amp;ldquo;hidden&amp;rdquo; prefs&lt;/a> being prefixed with &amp;ldquo;FRDebug&amp;rdquo;.&lt;/p>
&lt;p>As I understand it, the App\ Store.app invokes a binary inside &lt;code>/System/Library/PrivateFrameworks/CommerceKit.framework&lt;/code> called &amp;ldquo;storeagent&amp;rdquo; to do the actual downloading/talking to the dock. From looking at the &lt;a href="https://gist.github.com/768837">class-dump&lt;/a> of storeagent it communicates with the dock to place a new type of DockTile. Interesting sounding methods to (potentially?) swizzle are &lt;code>-[DownloadQueue sendDownloadListToDock]&lt;/code> and &lt;code>-[DownloadQueue tellDockToAddDownload:]&lt;/code>.&lt;/p>
&lt;p>I&amp;rsquo;ve given up for now, but I reckon it should be possible to create a bundle that swizzles the right methods in storeagent to stop it placing the downloads on the Dock.&lt;/p></description></item><item><title>Facebook iPhone app Contact Sync isn't automatic</title><link>https://caiustheory.com/facebook-iphone-app-contact-sync-isnt-automatic/</link><pubDate>Wed, 06 Oct 2010 14:10:06 +0000</pubDate><guid>https://caiustheory.com/facebook-iphone-app-contact-sync-isnt-automatic/</guid><description>&lt;p>There&amp;rsquo;s an article on the guardian about &lt;a href="http://www.guardian.co.uk/technology/blog/2010/oct/06/facebook-privacy-phone-numbers-upload">private phone numbers being uploaded from facebook&lt;/a>, and another over &lt;a href="http://www.techeye.net/security/facebook-takes-and-stores-data-numbers-from-your-iphone">techeye.net on the same subject.&lt;/a>&lt;/p>
&lt;p>Firstly a quote from the techeye article:&lt;/p>
&lt;blockquote>
&lt;p>Facebook doesn&amp;rsquo;t warn users that they are uploading their phone&amp;rsquo;s address book to Facebook.&lt;/p>
&lt;/blockquote>
&lt;p>And whilst the guardian article never says it happens automatically, it also doesn&amp;rsquo;t lay it out that you have to &lt;strong>explicitly&lt;/strong> enable that feature, &lt;strong>and&lt;/strong> agree to the facebook app uploading the data.&lt;/p>
&lt;p>I was pretty sure that facebook wouldn&amp;rsquo;t be grabbing all your contact information without telling you, if they did at all, and that both articles were just pure scaremongering. So I fired up the facebook iPhone app, headed into my friends list on there, clicked sync and got the following screen:&lt;/p>
&lt;p>&lt;img src="http://farm5.static.flickr.com/4148/5056619687_973ae660cc_d.jpg" alt="">&lt;br>
&lt;a href="http://www.flickr.com/photos/caius/5056619687/">View Original&lt;/a>&lt;/p>
&lt;p>Ok, so according to that text, they&amp;rsquo;re just pulling down profile images and profile links from facebook and putting them in your address book against your contacts. Seems fairly harmless so far. So I toggled the top switch, to enable Contact Sync, and got the following screen:&lt;/p>
&lt;p>&lt;img src="http://farm5.static.flickr.com/4145/5056697193_252e954ec3_d.jpg" alt="">&lt;br>
&lt;a href="http://www.flickr.com/photos/caius/5056697193/">View Original&lt;/a>&lt;/p>
&lt;p>Reading that, it&amp;rsquo;s fairly obvious what data facebook are uploading (although a little ambiguous why), and it &lt;strong>certainly&lt;/strong> isn&amp;rsquo;t happening automatically. As it says, it uploads the &amp;ldquo;name, email address, phone number&amp;rdquo; from all your contacts to facebook, and pull down &amp;ldquo;your friends&amp;rsquo; profile photos and other info from Facebook&amp;rdquo;.&lt;/p>
&lt;p>So whilst facebook &lt;em>are&lt;/em> collecting more data (albeit stored subject to their Privacy Policy), it&amp;rsquo;s certainly &lt;strong>NOT&lt;/strong> done automatically, and is &lt;strong>very explicit&lt;/strong> about what is being uploaded at the point you enable it.&lt;/p></description></item><item><title>+[NSObject load] in MacRuby</title><link>https://caiustheory.com/nsobject-load-in-macruby/</link><pubDate>Sat, 12 Jun 2010 02:11:32 +0000</pubDate><guid>https://caiustheory.com/nsobject-load-in-macruby/</guid><description>&lt;p>&lt;em>If you&amp;rsquo;ve not heard of it, &lt;a href="http://www.macruby.org/">MacRuby&lt;/a> is &lt;!-- raw HTML omitted -->an implementation of Ruby 1.9 directly on top of Mac OS X core technologies such as the Objective-C runtime and garbage collector, the LLVM compiler infrastructure and the Foundation and ICU frameworks.&lt;!-- raw HTML omitted --> Basically means you write in Ruby using Objective-C frameworks, and vice versa. It&amp;rsquo;s pretty damn cool to be honest!&lt;/em>&lt;/p>
&lt;h3 id="what-is-nsobject-load">What is +[NSObject load]?&lt;/h3>
&lt;p>From the &lt;a href="http://developer.apple.com/mac/library/documentation/cocoa/reference/foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/clm/NSObject/load">documentation&lt;/a>:&lt;/p>
&lt;blockquote>
&lt;p>Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading.&lt;/p>
&lt;/blockquote>
&lt;p>This means when your class is loaded, and implements the &lt;code>load&lt;/code> method, you get a &lt;code>load&lt;/code> message sent to your class. Which means you can start doing stuff as soon as your class is loaded by the runtime.&lt;/p>
&lt;p>The main place I&amp;rsquo;ve seen it used (and used it myself) is in &lt;a href="http://www.culater.net/software/SIMBL/SIMBL.php">SIMBL&lt;/a> plugins. A SIMBL plugin is an NSBundle that contains code which is loaded (injected) into a running application shortly after said application is launched. It lets you extend (or &amp;ldquo;fix&amp;rdquo;) cocoa applications with additional features. So you have this bundle of code, that gets loaded into a running application some point after it starts, and you want to run some code as the bundle is loaded - usually to kick off doing whatever you want to do in the plugin. This is where &lt;code>load&lt;/code> becomes useful.&lt;/p>
&lt;p>Here&amp;rsquo;s a quick implementation that just logs to the console:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-objc" data-lang="objc">&lt;span class="line">&lt;span class="cl"> &lt;span class="k">@implementation&lt;/span> &lt;span class="nc">MainController&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">load&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">NSlog&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">@&amp;#34;MainController#load called&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="now-where-does-macruby-come-into-this">Now where does MacRuby come into this?&lt;/h3>
&lt;p>Well I came across a need to do the same in ruby, have some code triggered when the class is loaded into the runtime. Tried implementing &lt;code>Class.load&lt;/code> but to no avail. Then remembered MacRuby is just ruby! And I can call any code from within my ruby class definition.&lt;/p>
&lt;p>For continuity I still call it &lt;code>Class.load&lt;/code>, but then call it as soon as I&amp;rsquo;ve defined it in the class. Eg:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">MainController&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nc">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nf">load&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">NSLog&lt;/span> &lt;span class="s2">&amp;#34;MainController#load called&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Of course, I&amp;rsquo;m not sure when the Objective-C method is called, it&amp;rsquo;s probably after the entire class has been defined rather than as soon as &lt;code>load&lt;/code> has been loaded into the runtime. So you might want to move the &lt;code>self.load&lt;/code> call to just before the closing &lt;code>end&lt;/code>.&lt;/p></description></item><item><title>Potty Training YAML</title><link>https://caiustheory.com/potty-training-yaml/</link><pubDate>Mon, 10 May 2010 21:46:17 +0000</pubDate><guid>https://caiustheory.com/potty-training-yaml/</guid><description>&lt;p>Ran into a problem today where I have a class with a few attributes on it, but I only want a certain three of those attributes to appear in the YAML dump of a class instance.&lt;/p>
&lt;p>Diving straight into a code example&amp;ndash;lets say we have a &lt;code>Contact&lt;/code> class, and we only want to dump the &lt;code>name&lt;/code>, &lt;code>email&lt;/code> and &lt;code>website&lt;/code> attributes.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">require&lt;/span> &lt;span class="s2">&amp;#34;yaml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Contact&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kp">attr_accessor&lt;/span> &lt;span class="ss">:name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:email&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:website&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">:telephone&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># helper method to make setting up easy&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">initialize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">params&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">each&lt;/span> &lt;span class="k">do&lt;/span> &lt;span class="o">|&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">meffod&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_s&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">=&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">send&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">meffod&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="nb">respond_to?&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">meffod&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># And create an instance for us to play with&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">caius&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Contact&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:name&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="s2">&amp;#34;Caius&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:email&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="s2">&amp;#34;dev@caius.name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:website&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="s2">&amp;#34;http://caius.name/&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">:telephone&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="s2">&amp;#34;12345&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As we&amp;rsquo;d expect when dumping this, all instance variables get dumped out:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">caius&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_yaml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; --- !ruby/object:Contact &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; email: dev@caius.name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; name: Caius&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; telephone: &amp;#34;12345&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; website: http://caius.name/&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Initially I tried to override &lt;code>to_yaml&lt;/code> and unset the instance variables I didn&amp;rsquo;t want showing up, but that just made them show up empty. After digging around a bit more, I happened across the &lt;a href="http://yaml4r.sourceforge.net/doc/page/type_families.htm">Type Families&lt;/a> page in the yaml4r docs, which right at the bottom mentions &lt;code>to_yaml_properties&lt;/code>.&lt;/p>
&lt;p>Turns out &lt;code>to_yaml_properties&lt;/code> returns an array of instance variable names (as strings) that should be dumped out as part of the object. A quick method definition later, and we&amp;rsquo;re only dumping the variables we want. (&lt;em>See my &lt;a href="http://caiustheory.com/ruby-shortcuts">Ruby Shortcuts&lt;/a> post if you don&amp;rsquo;t know what &lt;code>%w()&lt;/code> does&lt;/em>)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Contact&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">to_yaml_properties&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sx">%w(@name @email @website)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And now we dump the class, expecting only the three attributes to be outputted:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">caius&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_yaml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; --- !ruby/object:Contact &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; name: Caius&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; email: dev@caius.name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; website: http://caius.name/&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Success!&lt;/p></description></item><item><title>Ruby Shortcuts</title><link>https://caiustheory.com/ruby-shortcuts/</link><pubDate>Thu, 18 Mar 2010 22:32:45 +0000</pubDate><guid>https://caiustheory.com/ruby-shortcuts/</guid><description>&lt;p>There&amp;rsquo;s a few useful shorthand ways to create certain objects in Ruby, a couple of obvious ones are &lt;code>[]&lt;/code> to create an &lt;code>Array&lt;/code> and &lt;code>{}&lt;/code> to create a &lt;code>Hash&lt;/code> (Or block/&lt;code>Proc&lt;/code>). There&amp;rsquo;s some not so obvious ones too, for creating strings, regexes and executing shell commands.&lt;/p>
&lt;p>With all of the examples I&amp;rsquo;ve used &lt;code>{}&lt;/code> as the delimiter characters, but you can use a variety of characters. Personally I tend to use &lt;code>{}&lt;/code> unless the string contains them, in which case I&amp;rsquo;ll use &lt;code>//&lt;/code> or &lt;code>@@&lt;/code>. My only exception appears to be &lt;code>%w&lt;/code>, for which I tend to use &lt;code>()&lt;/code>.&lt;/p>
&lt;h3 id="strings">Strings&lt;/h3>
&lt;p>&lt;code>%&lt;/code> and &lt;code>%Q&lt;/code> are the same as using double quotes, including string interpolation. Really useful when you want to create a string that contains double quotes, but without the hassle of escaping them.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%{}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%Q{}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%{caius}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;caius&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%{caius &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sx">}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;caius 5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%{some &amp;#34;foo&amp;#34; thing}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;some \&amp;#34;foo\&amp;#34; thing&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>%q&lt;/code> is equivalent to using single quotes. Behaves exactly the same, no string interpolation.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%q{}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%q{caius}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;caius&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%q{caius #{5}}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;caius \#{5}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="arrays">Arrays&lt;/h3>
&lt;p>&lt;code>%w&lt;/code> is the equivalent of using String#split. It takes a string and splits it on whitespace. With the added bonus of being able to escape whitespace too. &lt;code>%W&lt;/code> allows string interpolation.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%w(foo bar sed)&lt;/span> &lt;span class="c1"># =&amp;gt; [&amp;#34;foo&amp;#34;, &amp;#34;bar&amp;#34;, &amp;#34;sed&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%w(foo\ bar sed)&lt;/span> &lt;span class="c1"># =&amp;gt; [&amp;#34;foo bar&amp;#34;, &amp;#34;sed&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%W(foo &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sx"> bar)&lt;/span> &lt;span class="c1"># =&amp;gt; [&amp;#34;foo&amp;#34;, &amp;#34;5&amp;#34;, &amp;#34;bar&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="regexes">Regexes&lt;/h3>
&lt;p>&lt;code>%r&lt;/code> is just like using &lt;code>//&lt;/code> to create a regexp object. Comes in handy when you&amp;rsquo;re writing a regex containing &lt;code>/&lt;/code> as you don&amp;rsquo;t have to continually escape it.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="sr">%r{foo|bar}&lt;/span> &lt;span class="c1"># =&amp;gt; /foo|bar/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sr">%r{foo/bar}&lt;/span> &lt;span class="c1"># =&amp;gt; /foo\/bar/&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="symbols">Symbols&lt;/h3>
&lt;p>&lt;code>%s&lt;/code> creates a symbol, just like writing &lt;code>:foo&lt;/code> manually. It takes care of escaping the symbol, but unlike &lt;code>:&amp;quot;&amp;quot;&lt;/code> it doesn&amp;rsquo;t allow string interpolation however.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%s{foo}&lt;/span> &lt;span class="c1"># =&amp;gt; :foo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%s{foo/bar}&lt;/span> &lt;span class="c1"># =&amp;gt; :&amp;#34;foo/bar&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="ss">:&amp;#34;foo-&lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="ss">&amp;#34;&lt;/span> &lt;span class="c1"># =&amp;gt; :&amp;#34;foo-5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%s{foo-#{5}}&lt;/span> &lt;span class="c1"># =&amp;gt; :&amp;#34;foo-\#{5}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="shelling-out">Shelling out&lt;/h3>
&lt;p>&lt;code>%x&lt;/code> is the same as backticks (&lt;!-- raw HTML omitted -->``&lt;!-- raw HTML omitted -->), executes the command in a shell and returns the output as a string. And just like backticks it supports string interpolation.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="sb">`echo hi`&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;hi\n&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%x{echo hi}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;hi\n&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sx">%x{echo &lt;/span>&lt;span class="si">#{&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sx">}&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;5\n&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>iPad? iPerfect (…for me)</title><link>https://caiustheory.com/ipad-iperfect-for-me/</link><pubDate>Wed, 27 Jan 2010 20:56:50 +0000</pubDate><guid>https://caiustheory.com/ipad-iperfect-for-me/</guid><description>&lt;p>&lt;em>Google Groups is a pile of fail and hasn&amp;rsquo;t posted my message in reply to a thread on &lt;a href="http://geekup.org/">Geekup&lt;/a> so I&amp;rsquo;m blogging it instead.&lt;/em>&lt;/p>
&lt;blockquote>
&lt;p>On 27 Jan 2010, at 19:53, Steve Richardson wrote:&lt;br>
Thoughts?&lt;/p>
&lt;/blockquote>
&lt;p>I&amp;rsquo;ve been searching for a device to fit between my Macbook Pro and iPhone. I work all day on the MBP, and moving it to then watch video in another room or read twitter/news/mail whilst watching telly, etc is a pain.&lt;/p>
&lt;p>The iPhone is a great little device on the move, but for trying to multitask at home it&amp;rsquo;s a bit.. tedious. Even jailbroken and running multiple apps at once it&amp;rsquo;s still limiting.&lt;/p>
&lt;p>I&amp;rsquo;d been looking around at netbooks, but what put me off actually getting one was my previous experience with one. I know I&amp;rsquo;d want it to run OS X to keep in sync (easily) with my other Apple devices, but hackintoshing one was a bit too much hassle, plus the fact ones to hackintosh cost more than I really wanted to pay for something that wasn&amp;rsquo;t &lt;em>quite&lt;/em> what I thought I needed.&lt;/p>
&lt;p>And then.. the iPad. I&amp;rsquo;ve been sort of keeping up with the rumours (mainly through &lt;a href="http://daringfireball.net">Daring Fireball&lt;/a>) and whilst I didn&amp;rsquo;t get excited about it too much ahead of announcement&lt;!-- raw HTML omitted -->1&lt;!-- raw HTML omitted -->, having seen the official video of it it&amp;rsquo;s pretty much guaranteed that I&amp;rsquo;m going to get one.&lt;/p>
&lt;p>Yes, it&amp;rsquo;s limited (App Store, closed device), but.. I don&amp;rsquo;t care. Take the iPhone, it&amp;rsquo;s good enough for doing things on it, even if someone else is in charge of the ecosystem and has a big finger saying yes or no. I (willingly) use iTunes, Mobile Me, all the things that are so wonderfully integrated in the world of Apple, so another device that consumes my media using channels I already know and use is just a massive win for me.&lt;/p>
&lt;p>All I&amp;rsquo;m hoping now is that $499 doesn&amp;rsquo;t equal £499. Hopefully it&amp;rsquo;ll be £399, still a good £80 above direct exchange rate, but low enough that it&amp;rsquo;s a no-brainer for me to get one.&lt;/p>
&lt;p>…And I think this is the first Apple product that I&amp;rsquo;ve seen announced and actually known from the start &lt;em>why&lt;/em> I&amp;rsquo;m going to get one, instead of just a knee-jerk &amp;ldquo;SHINY!!!! WANT!!!&amp;rdquo; reaction. Uh oh, does that make me an adult?&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->1&lt;!-- raw HTML omitted --> I miss getting really excited about apple announcements :(&lt;/p>
&lt;h4 id="update">Update&lt;/h4>
&lt;p>It just got even better. Was lamenting to a &lt;a href="http://tmertz.com/">friend&lt;/a> on IM that it&amp;rsquo;d be so much nicer once you can directly suck photos off a camera/SD card into it. Turns out there&amp;rsquo;s an adapter for that. See &amp;ldquo;iPad Camera Connection Kit&amp;rdquo; at the bottom of &lt;a href="http://www.apple.com/ipad/specs/">http://www.apple.com/ipad/specs/&lt;/a> for details.&lt;/p></description></item><item><title>at(1) on OS X</title><link>https://caiustheory.com/at-1-on-os-x/</link><pubDate>Mon, 28 Dec 2009 09:30:30 +0000</pubDate><guid>https://caiustheory.com/at-1-on-os-x/</guid><description>&lt;p>I recently came across the &lt;a href="http://developer.apple.com/mac/library/DOCUMENTATION/Darwin/Reference/ManPages/man1/at.1.html">&lt;code>at(1)&lt;/code>&lt;/a> command, and wondered why it wasn&amp;rsquo;t executing jobs I gave it on my machine. Had a poke around the man pages, and discovered in &lt;a href="http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man8/atrun.8.html">&lt;code>atrun(8)&lt;/code>&lt;/a> that by default &lt;code>launchd(8)&lt;/code> has the &lt;code>atrun&lt;/code> entry disabled.&lt;/p>
&lt;p>To enable it (and have &lt;code>at&lt;/code> jobs fire) you simply need to run the following command once:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Personally I&amp;rsquo;ve taken to using this to sleep my machine after a custom amount of time, mainly because my alarm clock/sleep timer of choice (&lt;a href="http://embraceware.com/awaken/">Awaken&lt;/a>) can&amp;rsquo;t handle playing &lt;a href="http://www.spotify.com/">Spotify&lt;/a> for x minutes and then sleeping the machine. The following command puts the machine to sleep, which (quite effectively) silences spotify.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;osascript -e &amp;#39;tell app \&amp;#34;Finder\&amp;#34; to sleep&amp;#39;&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> at 1:00am
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>See the &lt;a href="http://developer.apple.com/mac/library/DOCUMENTATION/Darwin/Reference/ManPages/man1/at.1.html">&lt;code>at(1)&lt;/code>&lt;/a> manpage for how to specify the time, but as I&amp;rsquo;m only ever scheduling it on the same day (usually 20 minutes or so in advance), just passing the time works fine.&lt;/p></description></item><item><title>Read Later in a keystroke</title><link>https://caiustheory.com/read-later-in-a-keystroke/</link><pubDate>Sun, 06 Dec 2009 22:15:37 +0000</pubDate><guid>https://caiustheory.com/read-later-in-a-keystroke/</guid><description>&lt;p>I use a wonderful service for saving text to be read later, &lt;a href="http://instapaper.com/">instapaper.com&lt;/a>. It&amp;rsquo;s gotten more wonderful as time has gone on and other applications/service&amp;rsquo;s have gained the ability to save links/articles/webpages there for me to pick up later.&lt;/p>
&lt;p>For instance, I&amp;rsquo;m out and about checking twitter on my iPhone using &lt;a href="http://atebits.com/tweetie-iphone/">tweetie&lt;/a> and someone tweets a link. Rather than wait for it to load and having to read it then and there I can just hit &amp;ldquo;Read Later&amp;rdquo; and it&amp;rsquo;s saved in my instapaper account for me to read as and when I choose to. Recently the legendary mac feed reader &lt;a href="http://www.newsgator.com/INDIVIDUALS/NETNEWSWIRE/">NetNewsWire&lt;/a> gained this ability too.&lt;/p>
&lt;p>There&amp;rsquo;s a few ways to send a feed item to instapaper from within NNW. Firstly you can right-click and click &amp;ldquo;Send to Instapaper&amp;rdquo;.&lt;/p>
&lt;p>&lt;img src="http://farm3.static.flickr.com/2553/4163576297_ee60e26b53_o.jpg" alt="Send to Instapaper from contextual menu">&lt;br>
&lt;a href="http://www.flickr.com/photos/caius/4163576297">View Original on Flickr&lt;/a>&lt;/p>
&lt;p>Secondly there&amp;rsquo;s a menu item for it in the News menu, which also provides my chosen way of instapapering an item—the keyboard shortcut! ⌃P &lt;em>(control-P)&lt;/em>.&lt;/p>
&lt;p>&lt;img src="http://farm3.static.flickr.com/2748/4164341910_476f8ba539_o.jpg" alt="Send to Instapaper from News menu">&lt;br>
&lt;a href="http://www.flickr.com/photos/caius/4164341910">View Original on Flickr&lt;/a>&lt;/p>
&lt;p>So, in NNW I&amp;rsquo;m happily sending stuff to instapaper with the handy ⌃P shortcut, but that doesn&amp;rsquo;t exist in the third place I mark things to read later&amp;ndash;Safari! Up until now I&amp;rsquo;ve been using the standard &amp;ldquo;Read Later&amp;rdquo; bookmarklet that &lt;a href="http://instapaper.com/">instapaper.com&lt;/a> provides, and it&amp;rsquo;s got a spot on my Bookmarks Bar so I can easily click it.&lt;/p>
&lt;p>That doesn&amp;rsquo;t really help with the fact I&amp;rsquo;m hitting ⌃P in NNW, and it doesn&amp;rsquo;t work in Safari. Quite often I noticed myself hitting the key combination in Safari and wondering for a split second why it wasn&amp;rsquo;t sending the item to instapaper. Then the solution hit me!&lt;/p>
&lt;p>In OS X you can setup (and/or override) menu items with custom key combinations! Why hadn&amp;rsquo;t I remembered this before. Because the &amp;ldquo;Read Later&amp;rdquo; bookmark*(let)* is nested under the Bookmarks menu, it &lt;strong>is&lt;/strong> a menu item! A quick trip into the Keyboards Prefpane in System Preferences and a new binding later and voilâ, &amp;ldquo;Read Later&amp;rdquo; in Safari is bound to ⌃P and I can use it in both Safari and NNW.&lt;/p>
&lt;p>&lt;img src="http://farm3.static.flickr.com/2517/4163642801_a14250da65_o.jpg" alt="Filling in the form to bind the keyboard shortcut">&lt;br>
&lt;a href="http://www.flickr.com/photos/caius/4163642801">View Original on Flickr&lt;/a>&lt;/p></description></item><item><title>My Menubar Items</title><link>https://caiustheory.com/my-menubar-items/</link><pubDate>Sun, 06 Dec 2009 12:56:49 +0000</pubDate><guid>https://caiustheory.com/my-menubar-items/</guid><description>&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>This is a something that occasionally makes the rounds again, I&amp;rsquo;ve not seen it for a while and I&amp;rsquo;ve added some new items since I last remember documenting it. Thus, &lt;a href="http://twitter.com/macarne">@macarne&lt;/a> &lt;a href="http://twitter.com/macarne/status/6398125336">asking&lt;/a> what the app was that gives me stats prompted me to document my current menubar items.&lt;/p>
&lt;p>&lt;img src="http://farm3.static.flickr.com/2586/4162170875_1d1a8be4cf.jpg" alt="annotated-menubar by ©aius, on Flickr" title="annotated-menubar">&lt;/p>
&lt;p>&lt;a href="http://www.flickr.com/photos/caius/4162170875/">View original&lt;/a>&lt;/p>
&lt;ol>
&lt;li>&lt;a href="http://www.eidac.de/">SMCFanControl&lt;/a> - Lets me adjust the minimum speed of my fans.&lt;/li>
&lt;li>&lt;a href="http://atebits.com/tweetie-mac">Tweetie/mac&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://iscrobbler.sourceforge.net/">iScrobbler&lt;/a> - Scrobbles tunes iTunes plays&lt;/li>
&lt;li>&lt;a href="http://www.realmacsoftware.com/littlesnapper/">LittleSnapper&lt;/a> &lt;em>(Or more accurately the menubar icon is NanoSnapper, LittleSnapper is the full app.)&lt;/em> Mainly used for screen grabs.&lt;/li>
&lt;li>&lt;a href="http://www.orange-carb.org/SBM/">SlimBatteryMonitor&lt;/a> - Takes up less horizontal space than Apple&amp;rsquo;s menu item.&lt;/li>
&lt;li>Expresscard menu item - Lets me power off my &lt;a href="http://www.memoryc.com/storage/solidstatedisk/48gbfilematesolidgoexpresscardultra.html">Expresscard/34 SSD&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.ragingmenace.com/software/menumeters/">MenuMeters&lt;/a> - An old friend I&amp;rsquo;ve been using for as long as I can remember running OS X. Set to show (left to right)
&lt;ol>
&lt;li>Ram - &lt;strong>U&lt;/strong>sed and &lt;strong>F&lt;/strong>ree totals.&lt;/li>
&lt;li>Network - Graph + values.&lt;/li>
&lt;li>CPU - Graph per core. Probably the most useful out of the three.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Bluetooth&lt;/li>
&lt;li>Time Machine&lt;/li>
&lt;li>Modem - To dial on my Huawei E220 3G stick.&lt;/li>
&lt;li>Airport&lt;/li>
&lt;li>Sound&lt;/li>
&lt;li>Day/Time&lt;/li>
&lt;li>Fast User Switching - Not sure why I keep this in the menubar, only have one user and I lock my screen with a password protected screensaver.&lt;/li>
&lt;li>&lt;a href="http://www.viscosityvpn.com/">Viscosity&lt;/a> - VPN software. Pretty useful.&lt;/li>
&lt;li>Spotlight! - Occasionally this vanishes when spotlight decides to be a dick and eat ram/cpu reindexing my disk every few hours. Touch wood it hasn&amp;rsquo;t done it since 10.6.1.&lt;/li>
&lt;/ol></description></item><item><title>Read standard input using Objective-C</title><link>https://caiustheory.com/read-standard-input-using-objective-c/</link><pubDate>Sun, 06 Dec 2009 11:50:08 +0000</pubDate><guid>https://caiustheory.com/read-standard-input-using-objective-c/</guid><description>&lt;p>On a couple of occasions now I&amp;rsquo;ve wanted to read from &lt;code>STDIN&lt;/code> into an Objective-C command line tool, and both times I&amp;rsquo;ve had to hunt quite a bit to find the answer because nothing shows up in google for the search terms I used. &amp;ldquo;Objective-c read from stdin&amp;rdquo; and &amp;ldquo;objc read stdin&amp;rdquo; both turn up results ranging from using &lt;code>NSInputStream&lt;/code> to dropping some C++ in there.&lt;/p>
&lt;p>The answer is quite simple really, just use &lt;code>NSFileHandle&lt;/code>. More specifically &lt;code>+[NSFileHandle fileHandleWithStandardInput]&lt;/code>. You can then read all data currently in &lt;code>STDIN&lt;/code>, monitor it for new data and anything else you can do with a normal &lt;code>NSFileHandle&lt;/code>.&lt;/p>
&lt;p>And here&amp;rsquo;s some example code, reads all data from &lt;code>STDIN&lt;/code> and stores it into an NSString:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-objc" data-lang="objc">&lt;span class="line">&lt;span class="cl">&lt;span class="n">NSFileHandle&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">input&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">NSFileHandle&lt;/span> &lt;span class="n">fileHandleWithStandardInput&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">NSData&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">inputData&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">NSData&lt;/span> &lt;span class="nl">dataWithData&lt;/span>&lt;span class="p">:[&lt;/span>&lt;span class="n">input&lt;/span> &lt;span class="n">readDataToEndOfFile&lt;/span>&lt;span class="p">]];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">NSString&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">inputString&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[[&lt;/span>&lt;span class="n">NSString&lt;/span> &lt;span class="n">alloc&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nl">initWithData&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">inputData&lt;/span> &lt;span class="nl">encoding&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">NSUTF8StringEncoding&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>I&amp;rsquo;m using this in GarbageCollected apps, memory management without GC is left as an exercise to the user.&lt;/em>&lt;/p></description></item><item><title>Nissan Almera Self Diagnostic Menu</title><link>https://caiustheory.com/nissan-almera-self-diagnostic-menu/</link><pubDate>Mon, 28 Sep 2009 10:44:00 +0000</pubDate><guid>https://caiustheory.com/nissan-almera-self-diagnostic-menu/</guid><description>&lt;p>Here&amp;rsquo;s how to access the self diagnostic / configuration menu on a Nissan Almera 2003 SVE (N16):&lt;/p>
&lt;ol>
&lt;li>Start the engine&lt;/li>
&lt;li>Turn the radio on&lt;/li>
&lt;li>Turn the radio off&lt;/li>
&lt;li>Hold the info button in &lt;em>then:&lt;/em>&lt;/li>
&lt;li>Turn the volume knob up (clockwise) &lt;em>until:&lt;/em>&lt;/li>
&lt;li>Diagnostic menu appears&lt;/li>
&lt;/ol>
&lt;p>From here you can do various things: run self-diagnostics; reset/change the main service counter; various other tests for the climate control, sat nav system, etc.&lt;/p></description></item><item><title>Ignore .gitignore in Git</title><link>https://caiustheory.com/ignore-gitignore-in-git/</link><pubDate>Mon, 21 Sep 2009 06:00:00 +0000</pubDate><guid>https://caiustheory.com/ignore-gitignore-in-git/</guid><description>&lt;p>Recently I ran into an issue where I was working on a project which had files I wanted git to ignore, but I didn&amp;rsquo;t want to commit a &lt;code>.gitignore&lt;/code> file into the project. In case you don&amp;rsquo;t know, any files matching a pattern in &lt;code>.gitignore&lt;/code> in a git repository are ignored by git. (Unless the file(s) have already been committed, then they need removing from git before they are ignored.)&lt;/p>
&lt;p>Initially I figured I could just throw the patterns I needed excluded into my global &lt;code>~/.gitignore&lt;/code>, but quickly realised that I needed files matching these patterns to show up in other git repos, so going the global route really wasn&amp;rsquo;t an option. After some thought I wondered if you could make git ignore &lt;code>.gitignore&lt;/code>, whilst still getting it to ignore files matching the other patterns in the &lt;code>.gitignore&lt;/code>.&lt;/p>
&lt;p>Lets create a new empty repo to test this crazy idea in:&lt;/p>
&lt;pre>&lt;code>$ mkdir foo
$ cd foo
$ git init
Initialized empty Git repository in /Volumes/Brutus/Users/caius/foo/.git/
&lt;/code>&lt;/pre>
&lt;p>And create a couple of files for us to play with:&lt;/p>
&lt;pre>&lt;code>$ touch bar
$ touch baz
&lt;/code>&lt;/pre>
&lt;p>Ignore one of the files so we can check other matches are still ignored later on:&lt;/p>
&lt;pre>&lt;code>$ echo &amp;quot;baz&amp;quot; &amp;gt;&amp;gt; .gitignore
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to include in what will be committed)
#
# .gitignore
# bar
nothing added to commit but untracked files present (use &amp;quot;git add&amp;quot; to track)
&lt;/code>&lt;/pre>
&lt;p>Ok so far, but we can still see .gitignore in git, so now for the crazy shindig, ignore the ignore file:&lt;/p>
&lt;pre>&lt;code>$ echo &amp;quot;.gitignore&amp;quot; &amp;gt;&amp;gt; .gitignore
&lt;/code>&lt;/pre>
&lt;p>Lets see if it worked, or if we can still see our .gitignore:&lt;/p>
&lt;pre>&lt;code>$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to include in what will be committed)
#
# bar
nothing added to commit but untracked files present (use &amp;quot;git add&amp;quot; to track)
&lt;/code>&lt;/pre>
&lt;p>And lets just double-check that &lt;code>.gitignore&lt;/code> and &lt;code>baz&lt;/code> still exist on the filesystem:&lt;/p>
&lt;pre>&lt;code>$ ls -a
. .. .git .gitignore bar baz
&lt;/code>&lt;/pre>
&lt;p>Fantastic! Turns out adding &amp;ldquo;.gitignore&amp;rdquo; to &lt;code>.gitignore&lt;/code> works perfectly. The file is still parsed by git to ignore everything else too, so it does exactly what I needed in this instance.&lt;/p></description></item><item><title>Filter through command</title><link>https://caiustheory.com/filter-through-command/</link><pubDate>Mon, 14 Sep 2009 22:39:37 +0000</pubDate><guid>https://caiustheory.com/filter-through-command/</guid><description>&lt;p>&lt;em>This is another old post that I&amp;rsquo;m republishing. Originally published 27th April 2007.&lt;/em>&lt;/p>
&lt;p>My text editor &lt;a href="http://macromates.com/">TextMate&lt;/a> has a nice feature called &amp;ldquo;Filter through command&amp;rdquo; whereby you can filter the current document through a command.&lt;/p>
&lt;p>Anyway, I&amp;rsquo;ve never used it before, but today I had a text file with 30 or so url&amp;rsquo;s in, each on a new line, so I thought I&amp;rsquo;d test it out. I selected it to input the document &amp;amp; to not replace the output. I then entered the following command, which is a ruby command to take each line that isn&amp;rsquo;t blank, and run the shell command &lt;code>open $url&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">ruby -e &lt;span class="s1">&amp;#39;a = ARGF.read.scan(/\S+/); a.each { |x| `open #{x}` }&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What this does is take ARGF (the document) and read it in line by line, but only the non-whitespace characters (so newlines, space, etc are ignored.) And it assigns it to an array called &lt;code>a&lt;/code>. What I then do is for each item of &lt;code>a&lt;/code>, we run it past the shell command &lt;code>open&lt;/code>, which on OS X if you pass it a URL it just opens that URL in the default browser.&lt;/p>
&lt;p>My browser is Safari, and its set to open new links in a new tab in the foremost window. So I ran the command, and hey presto, within a few seconds I had all the URL&amp;rsquo;s loading in seperate tabs in Safari&amp;rsquo;s foremost window!&lt;/p>
&lt;p>The power of Unix &lt;em>(OS X)&lt;/em> &amp;amp; TextMate (amongst other tools) just never ceases to amaze me.&lt;/p>
&lt;p>&lt;strong>Update&lt;/strong>&lt;/p>
&lt;p>I just realised if you change the regex to scan for http://.* then it&amp;rsquo;ll select all website URLs.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">ruby -e &lt;span class="s1">&amp;#39;a = ARGF.read.scan(/^http://.*$/); a.each { |url| `open #{url}` }&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Mac Tips you may not know</title><link>https://caiustheory.com/mac-tips-you-may-not-know/</link><pubDate>Mon, 31 Aug 2009 13:08:48 +0000</pubDate><guid>https://caiustheory.com/mac-tips-you-may-not-know/</guid><description>&lt;p>Here are some mac tips I know and consider &amp;ldquo;basic&amp;rdquo; mac knowledge, but no-one else seems to know.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>exposé&lt;/strong> key is on modern mac keyboards, looks like a load of squares on the F3 key.&lt;/li>
&lt;li>&lt;strong>⌘ + Exposé key&lt;/strong> =&amp;gt; Show Desktop&lt;/li>
&lt;li>&lt;strong>⌃ + Exposé key&lt;/strong> =&amp;gt; Show Application Windows&lt;/li>
&lt;li>&lt;strong>⌥ + Brightness keys&lt;/strong> =&amp;gt; Open Displays prefpane in System Preferences.&lt;/li>
&lt;li>&lt;strong>⌥ + Exposé key&lt;/strong> =&amp;gt; Open Exposé &amp;amp; Spaces prefpane in System Preferences.&lt;/li>
&lt;li>&lt;strong>⌥ + Dashboard key&lt;/strong> =&amp;gt; Open Exposé &amp;amp; Spaces prefpane in System Preferences.&lt;/li>
&lt;li>&lt;strong>⌥ + Keyboard Backlight keys&lt;/strong> =&amp;gt; Open Keyboard prefpane in System Preferences. &lt;em>(Only on laptops with keyboard backlighting.)&lt;/em>&lt;/li>
&lt;li>&lt;strong>⌥ + Volume keys&lt;/strong> =&amp;gt; Open Sound prefpane in System Preferences.&lt;/li>
&lt;li>&lt;strong>⇧ + Volume keys&lt;/strong> =&amp;gt; Adjust the volume with the feedback noise setting toggled. If you normally have feedback &amp;ldquo;blips&amp;rdquo;, it&amp;rsquo;ll be silent. Or vice versa.&lt;/li>
&lt;li>&lt;strong>⌥ + ⇧ + Volume keys&lt;/strong> =&amp;gt; Adjust the volume in 1/4 of a usual step.&lt;/li>
&lt;li>&lt;strong>⌃ + Eject key&lt;/strong> =&amp;gt; Shows the Shut Down dialog.&lt;/li>
&lt;li>In the shut down dialog, hit &lt;em>R&lt;/em> to restart, &lt;em>S&lt;/em> to sleep, &lt;em>⎋&lt;/em> to cancel.&lt;/li>
&lt;li>(Pretty much) Any dialog that pops up, hitting &lt;em>⎋&lt;/em> will push the &amp;ldquo;cancel&amp;rdquo; button.&lt;/li>
&lt;li>In &amp;ldquo;Show all windows&amp;rdquo; or &amp;ldquo;Show application windows&amp;rdquo; exposé modes, hit the tab key to cycle through applications.&lt;/li>
&lt;li>Hit the space bar in exposé to activate &amp;ldquo;Quick Look&amp;rdquo; + windows pop up to 100% size as you mouse over them.&lt;/li>
&lt;li>Hold down &lt;strong>⌃ + ⇧&lt;/strong> when mousing over the dock to toggle magnification whilst the keys are down.&lt;/li>
&lt;/ul>
&lt;p>&lt;em>(Alternative title &lt;a href="http://www.petercooper.co.uk/">Peter Cooper&lt;/a> suggested, &amp;ldquo;A miscellany of input device co-ordinations to modulate the response of Apple&amp;rsquo;s task preview and switching subsystem&amp;rdquo;)&lt;/em>&lt;/p></description></item><item><title>Education Network Restrictions</title><link>https://caiustheory.com/education-network-restrictions/</link><pubDate>Fri, 31 Jul 2009 14:14:16 +0000</pubDate><guid>https://caiustheory.com/education-network-restrictions/</guid><description>&lt;p>&lt;em>This is a re-run of an old post I took offline in an old server move and hadn&amp;rsquo;t re-published.&lt;/em>&lt;/p>
&lt;hr>
&lt;p>Having been on two college systems and various university networks, I&amp;rsquo;m just amazed at the levels of freedom you have on some, and how locked down others are.&lt;/p>
&lt;p>Take the first university network I ever used for example. It was pretty much totally open, to the point that I could game quite freely, and the administrator only picked me up because I was logged in as admin and not a normal user. (I didn&amp;rsquo;t have an account for that machine.)&lt;/p>
&lt;p>Going from that to my school network was a very big shock as it was moderately filtered through third party filtering software. This meant you couldn&amp;rsquo;t go on the usual &lt;a href="http://en.wikipedia.org/wiki/NSFW" title="Not Safe for Work">NSFW&lt;/a> stuff, but still had access to other sites that could be seen as bad, such as proxy sites, or IRC java Clients for example.&lt;/p>
&lt;p>Having moved from my old (slightly crass) college to my new one, its interesting how filtered this one is. You can&amp;rsquo;t seem to go on a site with &lt;code>proxy&lt;/code> or &lt;code>irc&lt;/code> in the URL, except &lt;em>clean&lt;/em> sites like the &lt;a href="http://www.bbc.co.uk/" title="British Broadcasting Corporation">BBC&lt;/a> or &lt;a href="http://wikipedia.org/" title="Wikipedia in English">Wikipedia&lt;/a>. The Proxy searching only came about through looking for web based IRC solutions.&lt;/p>
&lt;p>Personally I think the universities have got it right. With all the students they have, they just limit the things they definitely have to, and allow everything else. (Blacklisting technique.) Both colleges seem to do the opposite - block everything until its verified and unblocked. (Whitelisting technique.)&lt;/p>
&lt;p>The way I see it, the problem with the white listing technique is that people will always find a way around whatever restrictions are in place. For instance, I&amp;rsquo;m locked out of all of my web based email sites, so I can&amp;rsquo;t email anyone. Its not the not being able to send that bothers me, its the not being able to save text that I&amp;rsquo;ve written in college to a website to then retrieve it from home that annoys me.&lt;/p>
&lt;p>So how did I work around this restriction? Well I remembered that Google had bought &lt;a href="http://writely.com/" title="Collaborative Writing on the web">Writely&lt;/a> at some point recently, so one quick sign in later and I&amp;rsquo;ve got my own little area where I can save, organise and edit text based files. All I have to do when I get home is login, copy / paste into my email client and hit send.&lt;/p>
&lt;p>One word that isn&amp;rsquo;t blocked yet is &lt;code>blog&lt;/code>, so I can still post this, and edit my posts. However, I&amp;rsquo;m still writing it in &lt;a href="http://writely.com/" title="Collaborative Writing on the web">Writely&lt;/a> and checking my &lt;a href="http://daringfireball.net/projects/markdown/" title="Markup HTML without HTML">markdown&lt;/a> syntax is correct with &lt;a href="http://daringfireball.net/projects/markdown/dingus/" title="Preview and Practice MarkDown &amp;amp; SmartyPants">Dingus&lt;/a>. The writely interface is just that much nicer than notepad.&lt;/p></description></item><item><title>Capitalise "ringer" on the iPhone Volume Bezel</title><link>https://caiustheory.com/capitalise-ringer-on-the-iphone-volume-bezel/</link><pubDate>Sat, 20 Jun 2009 15:44:04 +0000</pubDate><guid>https://caiustheory.com/capitalise-ringer-on-the-iphone-volume-bezel/</guid><description>&lt;p>&lt;strong>Backstory:&lt;/strong> Got myself a first generation iPhone second hand and unlocked it to work on my existing T-Mobile (Official iPhone network in the UK is O2.) Noticed after a week or so of owning it that when you change the volume on the phone, the bezel that comes up says &amp;ldquo;ringer&amp;rdquo; across the top. But when you have headphones plugged in, it says &amp;ldquo;Headphones&amp;rdquo;. &lt;em>(Note the capitalisation difference.)&lt;/em>&lt;/p>
&lt;p>Now I&amp;rsquo;m not usually bothered by stuff like this (honest!) but as soon as I&amp;rsquo;d noticed the &lt;em>&amp;ldquo;bug&amp;rdquo;&lt;/em>, I couldn&amp;rsquo;t help but think of it everytime I changed the volume, whether I was looking at the screen or not. Seeing as I&amp;rsquo;m running a jailbroken phone, and therefore have SSH access to it, I figured the string would be defined in a .strings file somewhere in the &lt;code>/System&lt;/code> folder. And I&amp;rsquo;d be able to change it!&lt;/p>
&lt;p>Fast-forward a few months and I install the iPhone OS 3.0 update (jailbroken of course), and finally decide to turn the phone&amp;rsquo;s SSH server on and go looking for the setting. To do so I figured I&amp;rsquo;d just need &lt;code>grep&lt;/code> installed on the phone - I could copy the file itself to my mac and edit it there.&lt;/p>
&lt;p>So I connect to the phone, have a poke around the filesystem and then start a search to find the correct file:&lt;/p>
&lt;pre>&lt;code># On the iPhone
$ cd /System/Library/
$ grep -r &amp;quot;ringer&amp;quot; *
Binary file CoreServices/SpringBoard.app/English.lproj/SpringBoard.strings matches
Binary file CoreServices/SpringBoard.app/M68AP.plist matches
Binary file CoreServices/SpringBoard.app/SpringBoard matches
Binary file Frameworks/CFNetwork.framework/CFNetwork matches
Binary file Frameworks/CFNetwork.framework/da.lproj/Localizable.strings matches
Binary file Frameworks/CFNetwork.framework/no.lproj/Localizable.strings matches
Binary file Frameworks/Foundation.framework/da.lproj/URL.strings matches
&lt;/code>&lt;/pre>
&lt;p>At which point I stopped the grep search (&lt;code>^C&lt;/code>) because I know the home screen of the iPhone is the SpringBoard.app, so I figured it would be in the file &lt;code>SpringBoard.app/English.lproj/SpringBoard.strings&lt;/code>. Making sure to have SSH enabled on your mac, a simple &lt;code>scp CoreServices/SpringBoard.app/English.lproj/SpringBoard.strings user@your_mac.local:&lt;/code> later and the file is sat in my home folder on my mac.&lt;/p>
&lt;p>Switching to the mac, now I try and open the file with TextMate, only to realise its in binary format. I need it in the nice XML format to edit it, so a quick google later and I&amp;rsquo;ve found a hint on &lt;a href="http://macosxhints.com">MacOSXHints&lt;/a> telling me how to convert from &lt;a href="http://www.macosxhints.com/article.php?story=20050430105126392">binary to xml plist format&lt;/a>.&lt;/p>
&lt;pre>&lt;code># On the mac
$ plutil -convert xml1 SpringBoard.strings
&lt;/code>&lt;/pre>
&lt;p>Then opening the file in TextMate was a bit more successful! I can actually understand what its defining now. Search through the file for &amp;ldquo;ringer&amp;rdquo; and I found the following lines:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;key&amp;gt;&lt;/span>RINGER_VOLUME&lt;span class="nt">&amp;lt;/key&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;string&amp;gt;&lt;/span>ringer&lt;span class="nt">&amp;lt;/string&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Change the &amp;ldquo;ringer&amp;rdquo; to &amp;ldquo;Ringer&amp;rdquo; between the &lt;code>&amp;lt;string&amp;gt;&lt;/code> and my editing work is complete! Yes, it really is that easy to edit an interface string that is defined in a &lt;code>.string&lt;/code>. Now I just need to convert the file back to binary, and copy it back to the phone. Converting back to binary file is one line, just change the &lt;code>xml1&lt;/code> in the previous command to &lt;code>binary1&lt;/code>.&lt;/p>
&lt;pre>&lt;code># On the mac
$ plutil -convert binary1 SpringBoard.strings
&lt;/code>&lt;/pre>
&lt;p>And then scp it back to the phone, make a backup of the existing file, and overwrite the existing file with the new one I&amp;rsquo;ve edited:&lt;/p>
&lt;pre>&lt;code># On the iPhone
$ cd ~
$ scp user@mac_name.local:SpringBoard.strings .
$ cd /System/Library/CoreServices/SpringBoard.app/English.lproj/
$ mv SpringBoard.strings SpringBoard.strings.bak
$ cp ~/SpringBoard.strings SpringBoard.strings
&lt;/code>&lt;/pre>
&lt;p>And then restart the phone, either in the usual manner or just run &lt;code>reboot&lt;/code> on the phone via SSH. Lo and behold once its rebooted and I changed the volume, it read &amp;ldquo;Ringer&amp;rdquo;!&lt;/p>
&lt;p>&lt;img src="http://caius.name/images/ringer.jpg" alt="Screenshot of Volume bezel">&lt;/p></description></item><item><title>Adding XHTML output validation to Cucumber stories</title><link>https://caiustheory.com/adding-xhtml-output-validation-to-cucumber-stories/</link><pubDate>Tue, 16 Jun 2009 10:19:11 +0000</pubDate><guid>https://caiustheory.com/adding-xhtml-output-validation-to-cucumber-stories/</guid><description>&lt;p>At the 2009 &lt;a href="http://barcampleeds.com/">Barcamp Leeds&lt;/a> I attended a talk by &lt;a href="http://neilcrosby.com/vcard/">Neil Crosby&lt;/a> where he talked about automated testing, and about how he felt there was a gap in everything that people were testing. Everyone has unit tests, and people are doing full stack testing too, but no-one (so he feels) does XHTML/CSS/JS validation as part of their automated test suite. And certainly from what I&amp;rsquo;ve seen on the mainstream Ruby site&amp;rsquo;s about testing, I agreed with him.&lt;/p>
&lt;p>So after his talk I had a quick look at his &lt;a href="http://github.com/NeilCrosby/frontend-test-suite/tree/master">frontend test suite&lt;/a>, and started wondering where exactly I would fit frontend validation testing into my workflow. Would it be part of my unit tests (RSpec), or part of the full stack tests (Cucumber)? As you&amp;rsquo;ve probably guessed by the title of this post, its ended up going into my cucumber tests. Since the initial play its been something I&amp;rsquo;ve mused about occasionally, but not something I&amp;rsquo;ve actively looked into how to implement as part of my test workflow.&lt;/p>
&lt;p>Fast-forward a few weeks from &lt;a href="http://barcampleeds.com/">Barcamp Leeds&lt;/a> and I see a news article in my feed reader entitled &lt;a href="http://tenderlovemaking.com/2009/06/12/easy-markup-validation/">&amp;ldquo;Easy Markup Validation&amp;rdquo;&lt;/a> which gets me hopeful someone&amp;rsquo;s solved this frontend validation thing easily for Rubyists. A quick read through and I&amp;rsquo;m sold on it and installing the gem. Opened an existing project I&amp;rsquo;m working on which has a fairly extensive test suite (both unit tests &amp;amp; full stack tests) and tried to slot the validation into my controller unit tests.&lt;/p>
&lt;p>Problem with doing this is by default RSpec-rails doesn&amp;rsquo;t generate the views in your controller specs. At that point I realised I was already generating the full page when I was doing a full stack test using &lt;a href="http://github.com/langalex/culerity/tree/master">culerity&lt;/a> and &lt;a href="http://cukes.info/">cucumber&lt;/a>. So why not just add a cucumber step in my stories to validate the HTML on each page I visit? Mainly because its not enough of a failure for this app to have invalid XHTML markup. Having valid markup would be nice, but I&amp;rsquo;d rather have it as a separate test to my stories in some way.&lt;/p>
&lt;p>Currently I just do that by only validating if &lt;code>ENV[&amp;quot;VALIDATION&amp;quot;]&lt;/code> is set to anything, so a normal run of my cucumber stories will just test the app does what its supposed to do. If I run them with &lt;code>VALIDATION=true&lt;/code> then it will check my markup is valid as well.&lt;/p>
&lt;p>&lt;strong>features/support/env.rb&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">require&lt;/span> &lt;span class="s2">&amp;#34;markup_validity&amp;#34;&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="no">ENV&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;VALIDATION&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>features/step_definitions/general_steps.rb&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="no">Then&lt;/span> &lt;span class="s">%r/the page is valid XHTML/&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vg">$browser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">should&lt;/span> &lt;span class="n">be_xhtml_strict&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="no">ENV&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;VALIDATION&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>features/logging_in.feature&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-cucumber" data-lang="cucumber">&lt;span class="line">&lt;span class="cl">&lt;span class="k">Feature:&lt;/span>&lt;span class="nf"> Logging in
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> In order to do stuff
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> As a registered user
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> I want to login
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">Scenario:&lt;/span>&lt;span class="nf"> Successful Login
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">&lt;/span>&lt;span class="k"> Given &lt;/span>&lt;span class="nf">there is a user called &amp;#34;&lt;/span>&lt;span class="s">Caius&lt;/span>&lt;span class="nf">&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">When &lt;/span>&lt;span class="nf">I goto the homepage
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">Then &lt;/span>&lt;span class="nf">the page is valid XHTML
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">When &lt;/span>&lt;span class="nf">I click on the &amp;#34;&lt;/span>&lt;span class="s">Login&lt;/span>&lt;span class="nf">&amp;#34; link
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">Then &lt;/span>&lt;span class="nf">I am redirected to the login page
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">And &lt;/span>&lt;span class="nf">the page is valid XHTML
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">When &lt;/span>&lt;span class="nf">I enter my login details
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">And &lt;/span>&lt;span class="nf">I click &amp;#34;&lt;/span>&lt;span class="s">Login&lt;/span>&lt;span class="nf">&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">Then &lt;/span>&lt;span class="nf">I am redirected to my dashboard
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf"> &lt;/span>&lt;span class="k">And &lt;/span>&lt;span class="nf">the page is valid XHTML
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now when I run &lt;code>cucumber features/logging_in.feature&lt;/code>, it doesn&amp;rsquo;t validate the HTML, it just makes sure that I can login as my user and that I am redirected to the right places. But if I run &lt;code>VALIDATION=true cucumber features/logging_in.feature&lt;/code>, then it &lt;em>does&lt;/em> validate my XHTML on the homepage, the login page and on the user&amp;rsquo;s dashboard. If it fails validation then it gives you a fairly helpful error message as to what it was expecting and what it found instead.&lt;/p>
&lt;p>From a quick run against a couple of stories in my app I discovered that I&amp;rsquo;ve not been wrapping form elements in an enclosing element, so they&amp;rsquo;ve been quickly fixed and now they validate. Now I realise this gem is only testing XHTML output, and doesn&amp;rsquo;t include CSS or JS validation, but from a quick peek at the gem&amp;rsquo;s source it should be fairly easy to add both of those in I think, although again they aren&amp;rsquo;t major errors for me yet in this app.&lt;/p></description></item><item><title>Quantum Javascript Bug</title><link>https://caiustheory.com/quantum-javascript-bug/</link><pubDate>Thu, 04 Jun 2009 15:12:24 +0000</pubDate><guid>https://caiustheory.com/quantum-javascript-bug/</guid><description>&lt;p>So I&amp;rsquo;ve got some js I&amp;rsquo;ve written to update a couple of &lt;code>&amp;lt;select&amp;gt;&lt;/code> lists in a form, and it was all working fine for me (under Safari.) &lt;a href="http://johnleach.co.uk/">John&lt;/a> happened to mention it wasn&amp;rsquo;t working for him under Firefox, so I fired up Firefox and took a look. Could reproduce it perfectly, changing the first popup was populating the second one, but then wasn&amp;rsquo;t selecting the right value from the list.&lt;/p>
&lt;p>Having no idea what was happened I figured I&amp;rsquo;d enable firebug and watch it execute to figure out what was happening. Enabled firebug, reloaded the page, selected from the first popup… and &lt;strong>voila!&lt;/strong> It updated the second one and selected the correct row! WTF!!!&lt;/p>
&lt;p>Turned firebug off and it didn&amp;rsquo;t work, turned it back on and it worked. Figured it might be something buggy in the Firefox 3.0.5 js runtime, so I grabbed a copy of the new &lt;a href="http://www.mozilla.com/en-US/firefox/all-beta.html">beta 3.5&lt;/a> and tried it in there—still failed to update the page as it should.&lt;/p>
&lt;p>Then started poking around the javascript code, the function that was seemingly failing to run was being triggered by a setTimeout() call set to 1 second. We figured it might be the timing causing it, so started playing around with the time, tried anything from ½ a second up to 4 seconds but still no joy in firefox with firebug turned off.&lt;/p>
&lt;p>Then &lt;a href="http://johnleach.co.uk/">John&lt;/a> went looking for the javascript errors in firefox (with firebug off) and discovered that it was throwing an error because &lt;code>window.console&lt;/code> didn&amp;rsquo;t exist. All of a sudden it made perfect sense! Safari has &lt;code>window.console.log()&lt;/code> for writing to the console log, as does firebug. But of course firefox &lt;em>without&lt;/em> firebug doesn&amp;rsquo;t!&lt;/p>
&lt;p>So the function was just exiting on that error. It was very weird initially to have it work perfectly as soon as the developer tools were enabled!&lt;/p></description></item><item><title>Automatically Deploying Website From Remote Git Repository</title><link>https://caiustheory.com/automatically-deploying-website-from-remote-git-repository/</link><pubDate>Sat, 30 May 2009 02:30:40 +0000</pubDate><guid>https://caiustheory.com/automatically-deploying-website-from-remote-git-repository/</guid><description>&lt;p>Before I start, I&amp;rsquo;ll just quickly run through where I put stuff on my server. Apache logs and config are in the ubuntu default folders: &lt;code>/var/log/apache2&lt;/code> and &lt;code>/etc/apache2/&lt;/code> respectively.&lt;/p>
&lt;pre>&lt;code>Websites: /home/caius/vhosts/&amp;lt;domain name&amp;gt;/htdocs
Git Repos: /home/caius/git/&amp;lt;domain name&amp;gt;.git
&lt;/code>&lt;/pre>
&lt;p>So I have a git repo locally, &lt;code>~/projects/somesite.com/&lt;/code>, and want to deploy it to my webserver. I&amp;rsquo;ll keep the git repo in &lt;code>~/git/&lt;/code> and set it up so that when I push to the repo &lt;em>(over ssh)&lt;/em> it will automatically checkout the new changes into the website&amp;rsquo;s htdocs folder.&lt;/p>
&lt;p>I&amp;rsquo;m assuming DNS is already setup (or I&amp;rsquo;ve used &lt;a href="http://github.com/bjeanes/ghost/tree/master">ghost&lt;/a> to map it locally.) And that I&amp;rsquo;ve setup the virtualhost in apache pointing at &lt;code>/home/caius/vhosts/somesite.com/htdocs&lt;/code> and reloaded apache so the config is in place.&lt;/p>
&lt;h2 id="remote-machine">Remote Machine&lt;/h2>
&lt;p>We create a bare git repo, then point the working tree at the docroot of our website. This means all the git stuff is kept in the &lt;code>somesite.git&lt;/code> folder, but the files themselves are checked out to the website&amp;rsquo;s folder. Then we setup a post-receive hook to update the worktree folder after new changes have been pushed to the repo.&lt;/p>
&lt;pre>&lt;code>$ cd git
$ mkdir somesite.git
$ cd somesite.git/
$ git init --bare
Initialized empty Git repository in /home/caius/git/somesite.git/
$ git --bare update-server-info
$ git config core.worktree /home/caius/vhosts/somesite.com/htdocs
$ git config core.bare false
$ git config receive.denycurrentbranch ignore
$ cat &amp;gt; hooks/post-receive
#!/bin/sh
git checkout -f
^D
$ chmod +x hooks/post-receive
&lt;/code>&lt;/pre>
&lt;h2 id="local-machine">Local Machine&lt;/h2>
&lt;p>And now on the client machine we add the remote repo as a git remote, and then push to it.&lt;/p>
&lt;pre>&lt;code>$ git remote add web ssh://myserver/home/caius/git/somesite.git
$ git push web +master:refs/heads/master
Counting objects: 3, done.
Writing objects: 100% (3/3), 229 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://myserver/home/caius/git/somesite.git
* [new branch] master -&amp;gt; master
&lt;/code>&lt;/pre>
&lt;h2 id="all-done">All Done&lt;/h2>
&lt;p>And now if you go to &lt;em>somesite.com&lt;/em> you&amp;rsquo;ll see the contents of your git repo there. (&lt;em>somesite.com&lt;/em> is just an example url though, I don&amp;rsquo;t actually own it!)&lt;/p>
&lt;h3 id="helpful-urls">Helpful URLs&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://toroid.org/ams/git-website-howto">http://toroid.org/ams/git-website-howto&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.mblondel.org/journal/2008/05/25/git-memo/">http://www.mblondel.org/journal/2008/05/25/git-memo/&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://tatey.com/2009/04/29/jekyll-meets-dreamhost-automated-deployment-for-jekyll-with-git.html">http://tatey.com/2009/04/29/jekyll-meets-dreamhost-automated-deployment-for-jekyll-with-git.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Find shell commands with which</title><link>https://caiustheory.com/find-shell-commands-with-which/</link><pubDate>Sun, 19 Apr 2009 15:02:04 +0000</pubDate><guid>https://caiustheory.com/find-shell-commands-with-which/</guid><description>&lt;p>So I have this command in my $PATH, &lt;code>apachectl&lt;/code>. Because I&amp;rsquo;m on a mac and I&amp;rsquo;ve installed apache2 through &lt;a href="http://macports.org/">MacPorts&lt;/a>, the command that gets found first is my macports install in &lt;code>/opt&lt;/code>. Up until now I&amp;rsquo;ve always known that &lt;code>which apachectl&lt;/code> will find that location, but to find any other locations of &lt;code>apachectl&lt;/code> I&amp;rsquo;d usually use &lt;code>locate&lt;/code> and &lt;code>egrep&lt;/code> together.&lt;/p>
&lt;p>Here&amp;rsquo;s my original workflow, lets find the location of the &lt;code>apachectl&lt;/code> being called when I don&amp;rsquo;t specify a path.&lt;/p>
&lt;pre>&lt;code>Julius:~ caius$ which apachectl
/opt/local/apache2/bin/apachectl
&lt;/code>&lt;/pre>
&lt;p>Simple enough. Now lets figure out what other locations there&amp;rsquo;s an &lt;code>apachectl&lt;/code> installed at.&lt;/p>
&lt;pre>&lt;code>Julius:~ caius$ locate apachectl | egrep &amp;quot;\/apachectl$&amp;quot;
/opt/local/apache2/bin/apachectl
/opt/local/var/macports/software/apache2/2.2.11_0+darwin_9/opt/local/apache2/bin/apachectl
/usr/sbin/apachectl
&lt;/code>&lt;/pre>
&lt;p>Right, so now I know where else a command exists in the filesystem called &lt;code>apachectl&lt;/code>, but I don&amp;rsquo;t know if any of those is in my $PATH, or what order they come in when searching through my $PATH. In this (old) workflow I&amp;rsquo;d have compared them to my $PATH manually as there&amp;rsquo;s so few of them.&lt;/p>
&lt;p>So I noticed &lt;a href="http://awhitebox.com">Ali&lt;/a> googling for the &lt;code>which&lt;/code> man page on IRC, and &lt;em>(quite stupidly)&lt;/em> poked fun at him for doing so. I then swallowed my ego and actually followed the link to the man page, and boy was I glad I did. Just shows with even a fairly simple command like &lt;code>which&lt;/code>, you sure don&amp;rsquo;t know everything!&lt;/p>
&lt;p>What I discovered was that &lt;code>which&lt;/code> has a single flag you can pass it, &lt;code>-a&lt;/code>. From the &lt;a href="https://www.freebsd.org/cgi/man.cgi?query=which&amp;amp;format=html">man page&lt;/a>:&lt;/p>
&lt;pre>&lt;code>-a print all matching pathnames of each argument
&lt;/code>&lt;/pre>
&lt;p>Right. So that &lt;code>locate | grep&lt;/code> command plus manually figuring out what is in my $PATH is really hard work then. &lt;code>which -a&lt;/code> should give us the same results, but a lot faster and with a lot less manual thought.&lt;/p>
&lt;pre>&lt;code>Julius:~ caius$ which -a apachectl
/opt/local/apache2/bin/apachectl
/usr/sbin/apachectl
&lt;/code>&lt;/pre>
&lt;p>And hey presto, yet another useful bit of bash knowledge for me, thanks to &lt;a href="http://awhitebox.com">Ali&lt;/a> not being afraid to &lt;!-- raw HTML omitted -->RTFM&lt;!-- raw HTML omitted -->!&lt;/p></description></item><item><title>Validating Data with Regular Expressions in Ruby</title><link>https://caiustheory.com/validating-data-with-regular-expressions-in-ruby/</link><pubDate>Sat, 11 Apr 2009 12:41:48 +0000</pubDate><guid>https://caiustheory.com/validating-data-with-regular-expressions-in-ruby/</guid><description>&lt;p>I happened to be sent a link to the &lt;a href="https://www.owasp.org/index.php/Main_Page">OWASP&lt;/a> paper on &lt;a href="https://www.owasp.org/images/8/89/Rails_Security_2.pdf">Rails Security&lt;/a> recently and started reading it. Partway in there&amp;rsquo;s a section on Regular Expressions, which opens with the following line:&lt;/p>
&lt;blockquote>
&lt;p>A common pitfall in Ruby&amp;rsquo;s regular expressions is to match the string&amp;rsquo;s beginning and end by &lt;code>^&lt;/code> and &lt;code>$&lt;/code>, instead of &lt;code>\A&lt;/code> and &lt;code>\z&lt;/code>.&lt;/p>
&lt;/blockquote>
&lt;p>Now I&amp;rsquo;ve never used &lt;code>\A&lt;/code> and &lt;code>\z&lt;/code> in my regular expressions to validate data, I&amp;rsquo;ve only ever used &lt;code>^&lt;/code> and &lt;code>$&lt;/code> assuming they matched the start and end of the string. This becomes an issue with validating data in rails, because &lt;code>%0A&lt;/code> (&lt;code>\n&lt;/code> URL encoded) is decoded by rails before passing the string to your model to validate.&lt;/p>
&lt;h2 id="testing-our-expectations">Testing our expectations&lt;/h2>
&lt;p>Lets say we want to validate the string as a username for our app. A username is 5 characters long and consists only of lowercase letters.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">regex&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sr">/^[a-z]{5}$/&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>First we make sure it matches the data we want it to:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;caius&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Excellent, that validated. Now we&amp;rsquo;ll try a shorter string, which we expect to fail.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;cai&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once more, it behaves how we expected it to. The shorter string was rejected as we wanted it to be. Now, what happens if we test a string with a newline character in it? We&amp;rsquo;ll make sure the data before the &lt;code>\n&lt;/code> is valid, and then add some more data after the newline.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;caius&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">foo&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Uh oh! That validated and would&amp;rsquo;ve been saved as a username?!&lt;/p>
&lt;p>Lets have a look at exactly what&amp;rsquo;s happening there, the &lt;code>$&lt;/code> matches the &lt;code>\n&lt;/code> character, so the regex is only matching the first 5 characters of the string, and just ignores anything after the &lt;code>\n&lt;/code>. As it turns out, this is exactly what we&amp;rsquo;ve asked the regex to match, but we didn&amp;rsquo;t want this behaviour.&lt;/p>
&lt;p>Now you might be thinking, &amp;ldquo;So what? someone can have a username with a newline in it.&amp;rdquo; For starters this will probably display weirdly anywhere you use their username, but more importantly it opens your application to an injection attack. Suppose they took advantage of this by setting their username to include some javascript on the page which stole your login cookie and sent it to them. You view their account in the admin section and oh no! They can login as your admin account and do what they want.&lt;/p>
&lt;p>Simple example of this is just having it output an alert dialog. &lt;em>(This is actually the code I&amp;rsquo;ll use to test an application as its not malicious, but blindingly obvious if the javascript is executed or not.)&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;caius&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;lt;script&amp;gt;alert(&amp;#39;hello&amp;#39;)&amp;lt;/script&amp;gt;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ok, so that was the result we were expecting this time, although it&amp;rsquo;s still not the outcome we wanted. Anytime their username is viewed (providing you aren&amp;rsquo;t escaping the data to HTML entities) you&amp;rsquo;ll see the following:&lt;/p>
&lt;p>&lt;img src="http://caius.name/images/qs/javascript-alert-dialog.png" alt="javascript alert dialog">&lt;/p>
&lt;h2 id="the-solution">The Solution&lt;/h2>
&lt;p>Having realised from our testing above that ^$ matches the beginning/end of a &lt;em>line&lt;/em> in ruby not the beginning and end of a &lt;em>string&lt;/em>, I hear you cry, &amp;ldquo;How do we make sure we&amp;rsquo;re matching the entire string?!&amp;rdquo;&lt;/p>
&lt;p>The answer is pretty simple. Just swap out &lt;code>^$&lt;/code> for &lt;code>\A\z&lt;/code>. Lets go ahead and try this with the same data as we have above, but with the modified regular expression.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">new_regex&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sr">/\A[a-z]{5}\z/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;caius&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s a good start, the valid string still matches.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;cai&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Looks like it&amp;rsquo;s going well, invalid string is invalid.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;caius&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">foo&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Oh Excellent! It&amp;rsquo;s validating this one correctly now.&lt;/p>
&lt;p>And just for consistency, lets test it with a more likely attack string.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;caius&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;lt;script&amp;gt;alert(&amp;#39;hello&amp;#39;)&amp;lt;/script&amp;gt;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_regex&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Fantastic! We&amp;rsquo;ve fixed the security hole in our validation of the user&amp;rsquo;s username.&lt;/p>
&lt;hr>
&lt;p>If you want to actually run the code above you&amp;rsquo;ll need the following at the start of the ruby script to patch the validate method into String.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">String&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">validate&lt;/span> &lt;span class="n">regex&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">!&lt;/span>&lt;span class="nb">self&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">regex&lt;/span>&lt;span class="o">].&lt;/span>&lt;span class="n">nil?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>&lt;strong>Update:&lt;/strong>&lt;/em> I had &lt;code>\Z&lt;/code> in the &lt;code>new_regex&lt;/code> rather than the &lt;code>\z&lt;/code> it should&amp;rsquo;ve been. Thanks &lt;a href="http://ciaranwal.sh/">Ciarán&lt;/a>.&lt;/p></description></item><item><title>Safari 4 Hidden Preferences</title><link>https://caiustheory.com/safari-4-hidden-preferences/</link><pubDate>Tue, 24 Feb 2009 16:11:05 +0000</pubDate><guid>https://caiustheory.com/safari-4-hidden-preferences/</guid><description>&lt;p>&lt;strong>Updated 2009-06-09:&lt;/strong> This post is for the Safari 4 &lt;strong>beta&lt;/strong> and will not work with the new Safari 4 released yesterday at the WWDC keynote. I&amp;rsquo;ve had a look through that release and can&amp;rsquo;t see any way to revert the address bar, etc sorry.&lt;/p>
&lt;hr>
&lt;p>Having a quick poke through the new Safari binary yields the following strings:&lt;/p>
&lt;pre>&lt;code>$ strings /Applications/Safari.app/Contents/MacOS/Safari | grep DebugSafari4
DebugSafari4TabBarIsOnTop
DebugSafari4IncludeToolbarRedesign
DebugSafari4IncludeFancyURLCompletionList
DebugSafari4IncludeGoogleSuggest
DebugSafari4LoadProgressStyle
DebugSafari4IncludeFlowViewInBookmarksView
DebugSafari4TopSitesZoomToPageAnimationDimsSnapshot
DebugSafari4IncludeTopSites
&lt;/code>&lt;/pre>
&lt;p>&lt;em>NB: Run these commands in Terminal.app and then you need to restart Safari for them to take effect.&lt;/em>&lt;/p>
&lt;h3 id="debugsafari4tabbarisontop">DebugSafari4TabBarIsOnTop&lt;/h3>
&lt;p>This moves the tab bar back where you expect it to be:&lt;/p>
&lt;pre>&lt;code>$ defaults write com.apple.Safari DebugSafari4TabBarIsOnTop -bool NO
&lt;/code>&lt;/pre>
&lt;h3 id="debugsafari4includetoolbarredesign-and-debugsafari4loadprogressstyle">DebugSafari4IncludeToolbarRedesign and DebugSafari4LoadProgressStyle&lt;/h3>
&lt;p>When both set to NO it restores the blue loading bar behind the URL. &lt;em>Also puts a page loading spinner in the tab itself, which looks odd with the new tabs.&lt;/em>&lt;/p>
&lt;pre>&lt;code>$ defaults write com.apple.Safari DebugSafari4IncludeToolbarRedesign -bool NO
$ defaults write com.apple.Safari DebugSafari4LoadProgressStyle -bool NO
&lt;/code>&lt;/pre>
&lt;h3 id="debugsafari4includefancyurlcompletionlist">DebugSafari4IncludeFancyURLCompletionList&lt;/h3>
&lt;p>Switches off the new URL autocomplete menu and goes back to the original one.&lt;/p>
&lt;pre>&lt;code>$ defaults write com.apple.Safari DebugSafari4IncludeFancyURLCompletionList -bool NO
&lt;/code>&lt;/pre>
&lt;h3 id="debugsafari4includegooglesuggest">DebugSafari4IncludeGoogleSuggest&lt;/h3>
&lt;p>Turns off the new Google suggest menu.&lt;/p>
&lt;pre>&lt;code>$ defaults write com.apple.Safari DebugSafari4IncludeGoogleSuggest -bool NO
&lt;/code>&lt;/pre>
&lt;h3 id="debugsafari4includeflowviewinbookmarksview">DebugSafari4IncludeFlowViewInBookmarksView&lt;/h3>
&lt;p>Removes CoverFlow from the Bookmarks view entirely. (&lt;a href="http://twitter.com/iacas/status/1245800183">Credit&lt;/a> to &lt;a href="http://nslog.com/">Erik&lt;/a>)&lt;/p>
&lt;pre>&lt;code>$ defaults write com.apple.Safari DebugSafari4IncludeFlowViewInBookmarksView -bool NO
&lt;/code>&lt;/pre>
&lt;h3 id="debugsafari4topsiteszoomtopageanimationdimssnapshot">DebugSafari4TopSitesZoomToPageAnimationDimsSnapshot&lt;/h3>
&lt;p>Disables the dimming when you click on a Top Site and it scales the screenshot up to fill the screen.&lt;/p>
&lt;pre>&lt;code>$ defaults write com.apple.Safari DebugSafari4TopSitesZoomToPageAnimationDimsSnapshot -bool NO
&lt;/code>&lt;/pre>
&lt;h3 id="debugsafari4includetopsites">DebugSafari4IncludeTopSites&lt;/h3>
&lt;p>Disables Top Sites feature completely.&lt;/p>
&lt;pre>&lt;code>$ defaults write com.apple.Safari DebugSafari4IncludeTopSites -bool NO
&lt;/code>&lt;/pre>
&lt;h2 id="undoing-changes">Undoing changes&lt;/h2>
&lt;p>Just run the defaults command with the &lt;code>delete&lt;/code> flag for the appropriate key you wish to delete.&lt;/p>
&lt;pre>&lt;code>$ defaults delete com.apple.Safari &amp;lt;key&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>&lt;em>NB: Don&amp;rsquo;t include the &lt;code>-bool NO&lt;/code> at the end, it just requires the key (eg: &amp;ldquo;DebugSafari4IncludeGoogleSuggest&amp;rdquo;)&lt;/em>&lt;/p>
&lt;h3 id="update-2009-02-26">Update 2009-02-26&lt;/h3>
&lt;p>&lt;a href="http://swedishcampground.com/safari-4-hidden-preferences#comment-3265">Jools points out in the comments&lt;/a> how to reset the recent searches in the google search box.&lt;/p>
&lt;h3 id="update-2009-05-26">Update 2009-05-26&lt;/h3>
&lt;p>Lowell&amp;rsquo;s kindly created a Mac OS X application to edit these settings without using Terminal. &lt;a href="http://github.com/cocoastep/tweaky">http://github.com/cocoastep/tweaky&lt;/a>&lt;/p>
&lt;h3 id="update-2010-11-18">Update 2010-11-18&lt;/h3>
&lt;p>Patric has kindly &lt;a href="http://www.movavi.com/opensource/safari-4-hidden-preferences-be">translated this post into Belorussian&lt;/a> and posted it on his site.&lt;/p></description></item><item><title>Migrating Rubygems to Ruby 1.9.x</title><link>https://caiustheory.com/migrating-rubygems-to-ruby-19x/</link><pubDate>Sat, 31 Jan 2009 20:29:57 +0000</pubDate><guid>https://caiustheory.com/migrating-rubygems-to-ruby-19x/</guid><description>&lt;p>So I just installed ruby 1.9.1 through &lt;a href="http://macports.org/">MacPorts&lt;/a> and wanted to easily migrate my rubygems across from 1.8 to see which ones would fail to install.&lt;/p>
&lt;p>Thought about it for a while, then came up with the following bash one-liner to do it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">gem list &lt;span class="p">|&lt;/span> grep &lt;span class="s2">&amp;#34;(&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> awk &lt;span class="s1">&amp;#39;{ print $1 }&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> xargs -L &lt;span class="m">1&lt;/span> gem1.9 install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>NB:&lt;/strong> Installing Ruby 1.9.1 through macports &lt;code>sudo port install ruby19&lt;/code> means I get &lt;code>ruby1.9&lt;/code>, &lt;code>gem1.9&lt;/code> and &lt;code>rake1.9&lt;/code> installed alongside my usual 1.8 &lt;code>ruby&lt;/code>, &lt;code>gem&lt;/code> and &lt;code>rake&lt;/code>.&lt;/p>
&lt;p>That grabs the list of installed gems from &lt;code>gem&lt;/code>, searches for lines containing &amp;ldquo;(&amp;rdquo; so it only grabs the gem names, spits out the first section of the line, which is the name of the gem, and finally calls &lt;code>gem1.9 install&lt;/code> for each line via &lt;code>xargs -L 1&lt;/code>. Make sure to run it as root or prefix &lt;code>gem1.9&lt;/code> with &lt;code>sudo&lt;/code>. &lt;em>(Or let it install in your home folder, but I hate that.)&lt;/em>&lt;/p>
&lt;p>From my quick run of the above snippet, 75% of my gems installed &lt;em>(73 out of 98)&lt;/em> and the other few that failed to install were ones like &lt;a href="http://github.com/why/hpricot/tree/master">Hpricot&lt;/a> that require native extensions compiling. You can see the entire list of failures and successes of the gems in &lt;a href="http://pastie.textmate.org/pastes/376136">this pastie&lt;/a>&lt;/p></description></item><item><title>View Raw Source</title><link>https://caiustheory.com/view-raw-source/</link><pubDate>Sat, 31 Jan 2009 01:54:57 +0000</pubDate><guid>https://caiustheory.com/view-raw-source/</guid><description>&lt;p>So I write this blog using &lt;a href="http://daringfireball.net/projects/markdown/">Markdown&lt;/a> because I&amp;rsquo;m a human and writing &lt;code>stuff &amp;lt;strong&amp;gt;with&amp;lt;/strong&amp;gt; tags&lt;/code> is just &lt;strong>WRONG&lt;/strong>. Thankfully, &lt;a href="http://daringfireball.net/">Gruber&lt;/a> solved this problem by writing markdown.&lt;/p>
&lt;p>Now on the &lt;a href="http://daringfireball.net/projects/markdown/">markdown page&lt;/a> he says:&lt;/p>
&lt;blockquote>
&lt;p>The best way to get a feel for Markdown’s formatting syntax is simply to look at a Markdown-formatted document. For example, you can view the Markdown source for the article text on this page here: &lt;a href="http://daringfireball.net/projects/markdown/index.text">http://daringfireball.net/projects/markdown/index.text&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>(You can use this ‘.text’ suffix trick to view the Markdown source for the content of each of the pages in this section, e.g. the Syntax and License pages.)&lt;/p>
&lt;/blockquote>
&lt;p>And ever since I noticed that I&amp;rsquo;ve always read his articles using the &amp;lsquo;.text&amp;rsquo; trick. One of the plugins I&amp;rsquo;ve been meaning to write for &lt;a href="http://habariproject.org/">habari&lt;/a> is one that replicates this &amp;lsquo;.text&amp;rsquo; behaviour. So tonight I decided to try and write it, started picking through the &lt;a href="http://wiki.habariproject.org/en/Creating_A_Plugin">Plugin documentation&lt;/a> in preparation. Got a bit stuck with it as I&amp;rsquo;ve been out of the habari development loop for a few months, popped into &lt;a href="irc://irc.freenode.net/#habari">#habari&lt;/a> and asked if I was thinking along the right lines.&lt;/p>
&lt;p>Few minutes later &lt;a href="http://asymptomatic.net/">Owen&lt;/a> pops up and sends me a link to &lt;a href="http://pastoid.com/bn5">plaintext.plugin.php&lt;/a>, which does exactly what I was trying to do! Couple of tweaks later (switching it to &amp;lsquo;.text&amp;rsquo; instead of &amp;lsquo;.md&amp;rsquo;) and its installed and working on this blog. Feel free to view the &lt;a href="http://caiustheory.com/view-raw-source.text">raw source&lt;/a> of this post. Or any other post on this site.&lt;/p>
&lt;h3 id="updated-2009-01-31">Updated 2009-01-31&lt;/h3>
&lt;p>Added to the habari-extras repo as the &lt;a href="http://pastoid.com/bn5">Plaintext&lt;/a> plugin.&lt;/p></description></item><item><title>This is my Compiler</title><link>https://caiustheory.com/this-is-my-compiler/</link><pubDate>Fri, 30 Jan 2009 12:18:56 +0000</pubDate><guid>https://caiustheory.com/this-is-my-compiler/</guid><description>&lt;p>As some friday fun in &lt;a href="http://twitter.com/geekupirc">#geekup&lt;/a> we ended up converting the &lt;a href="http://usmilitary.about.com/od/marines/l/blriflecreed.htm">US Marines Creed&lt;/a> to a geekier version.&lt;/p>
&lt;blockquote>
&lt;p>This is my compiler.&lt;br>
There are many like it, but this one is MINE.&lt;br>
My compiler is my best friend. It is my life.&lt;br>
I must master it as I must master my life.&lt;br>
My compiler without me is useless. Without my compiler, I am useless.&lt;br>
I must run my compiler true.&lt;br>
I must run faster than my bug who is trying to kill me.&lt;br>
I must squash him before he squashes me. I will&amp;hellip;&lt;br>
My compiler and myself know that what counts in war is not the warnings we squash,&lt;br>
the builds we create, nor the optimisations we make.&lt;br>
We know it is the build errors fixed that count. We will fix&amp;hellip;&lt;br>
My compiler is human, even as I, because it is my life.&lt;br>
Thus, I will learn it as a brother.&lt;br>
I will learn its weaknesses, its strengths, its output, its code,&lt;br>
its quirks, and its errors.&lt;br>
I will ever guard it against the ravages of virii and disk failures.&lt;br>
I will keep my compiler clean and ready, even as I am clean and ready.&lt;br>
We will become part of each other. We will&amp;hellip;&lt;br>
Before Assembler I swear this creed.&lt;br>
My compiler and myself are the defenders of good code.&lt;br>
We are the masters of our bugs.&lt;br>
We are the saviors of our code.&lt;br>
So be it, until code is compiling and there are no bugs, but compiled code.&lt;/p>
&lt;/blockquote>
&lt;p>And then &lt;a href="http://jamx.org/">jamx&lt;/a> jumped in with the &lt;a href="http://en.wikipedia.org/wiki/Lord's_Prayer#English_versions">Lords Prayer&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>Our Compiler, who art in memory. GNU be thy name.&lt;br>
Thy source code come, thy will be done.&lt;br>
On script as it is in memory.&lt;br>
Give us this day our daily data, and forgive us our segfaults as we forgive those who segfault against us.&lt;br>
And lead us not into /dev/null but deliver us from M$,&lt;br>
for thine is the domain, the cpu and the peeps.&lt;br>
for (x=0; x&amp;lt;2; x++){ x=0; }&lt;br>
Amen&lt;/p>
&lt;/blockquote></description></item><item><title>Install Mysql Gem on Leopard</title><link>https://caiustheory.com/install-mysql-gem-on-leopard/</link><pubDate>Wed, 21 Jan 2009 17:09:41 +0000</pubDate><guid>https://caiustheory.com/install-mysql-gem-on-leopard/</guid><description>&lt;p>So, I keep having to reinstall mysql5 and rubygems from time to time for various reasons. I always install mysql5 through &lt;a href="http://macports.org/">MacPorts&lt;/a> as a dependency for the php5 port (along with various other bits for the LA*P stack).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo port install php5 +mysql5 +pear +readline +sockets +apache2 +sqlite
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once this is installed then I have &lt;code>mysql&lt;/code> and can setup my databases, etc.&lt;/p>
&lt;p>Ignoring the rest of the LAMP stack, I then need to connect Ruby to the Mysql I just installed through MacPorts. Its quite simple to do, once you know the right argument to pass to it. The easiest way is to just tell it where the &lt;code>mysql5_conf&lt;/code> file is and let it figure out the rest for itself.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo gem install mysql -- --with-mysql-config&lt;span class="o">=&lt;/span>/opt/local/bin/mysql_config5
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hopefully this will save me 10 minutes of googling next time I need to do this!&lt;/p>
&lt;h3 id="update-2009-01-21">Update 2009-01-21&lt;/h3>
&lt;p>I&amp;rsquo;m an idiot and typed the &lt;code>gem install&lt;/code> command by hand, and ended up with &lt;code>--with-mysql-conf&lt;/code> instead of &lt;code>--with-mysql-config&lt;/code>. Updated now.&lt;/p>
&lt;h3 id="update-2009-10-19">Update 2009-10-19&lt;/h3>
&lt;p>On Snow Leopard I needed to tell rubygems to install the gem as a 64-bit binary. Hattip to &lt;a href="http://www.schmidp.com/2009/06/14/rubyrails-and-mysql-on-snow-leopard-10a380/comment-page-1/">Philipp&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo env &lt;span class="nv">ARCHFLAGS&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;-arch x86_64&amp;#34;&lt;/span> gem install mysql -- &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --with-mysql-config&lt;span class="o">=&lt;/span>/opt/local/bin/mysql_config5
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>GTranslate</title><link>https://caiustheory.com/gtranslate/</link><pubDate>Sun, 04 Jan 2009 09:40:59 +0000</pubDate><guid>https://caiustheory.com/gtranslate/</guid><description>&lt;p>I finally wrapped up some code I&amp;rsquo;ve been meaning to write for a while, its a wrapper for the &lt;a href="http://translate.google.com/">Google Translate API&lt;/a>. Its also the first serious time I&amp;rsquo;ve used &lt;code>method_missing&lt;/code> in a class, in this case its to add methods for translating between all the various languages.&lt;/p>
&lt;p>Its fairly simple to use, there is an &lt;a href="http://github.com/caius/gtranslate/tree/master/examples.rb">examples.rb&lt;/a> included with it, but the basic usage is just this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Convert from english to french&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">Google&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="no">Translate&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">english_to_french&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="s2">&amp;#34;Hello&amp;#34;&lt;/span> &lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;Bonjour&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># There is also a short(er)-hand version&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="no">Google&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="no">Tr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">en_to_fr&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="s2">&amp;#34;Hello&amp;#34;&lt;/span> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As per usual with all my code its available on my &lt;a href="http://github.com/caius/">github account&lt;/a>, as the &lt;a href="http://github.com/caius/gtranslate/">GTranslate&lt;/a> project. I&amp;rsquo;ll throw some specs together for it and package it up as a gem soon.&lt;/p></description></item><item><title>The Shell Meme</title><link>https://caiustheory.com/the-shell-meme/</link><pubDate>Tue, 30 Dec 2008 18:29:35 +0000</pubDate><guid>https://caiustheory.com/the-shell-meme/</guid><description>&lt;p>I ran across &lt;a href="http://lstoll.net/2008/04/shell-meme/">The Shell Meme&lt;/a> on &lt;a href="http://lstoll.net/">Lincoln Stoll&amp;rsquo;s&lt;/a> blog, and figured I&amp;rsquo;d, uh, &lt;em>borrow&lt;/em> it.&lt;/p>
&lt;p>Run this command in a new shell:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">history&lt;/span> &lt;span class="p">|&lt;/span> awk &lt;span class="s1">&amp;#39;{ a[$2]++ } END { for(i in a){printf &amp;#34;%5d\t%s\n &amp;#34;,a[i],i} }&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> sort -rn &lt;span class="p">|&lt;/span> head
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I get this as the output&lt;/p>
&lt;pre>&lt;code>379 git
221 cd
181 ssh
77 sudo
69 ruby
66 ls
34 rake
33 m
32 bb
31 m.
&lt;/code>&lt;/pre>
&lt;p>&lt;code>bb&lt;/code> changes directory straight into my &lt;a href="http://www.brightbox.co.uk/">BrightBox&lt;/a> source directory. &lt;code>m&lt;/code> and &lt;code>m.&lt;/code> are &lt;a href="http://macromates.com/">TextMate&lt;/a> alias&amp;rsquo;s to open files or directories in TextMate for editing.&lt;/p></description></item><item><title>Sending Array elements as individual arguments in Ruby</title><link>https://caiustheory.com/sending-array-elements-as-individual-arguments-in-ruby/</link><pubDate>Fri, 26 Dec 2008 07:25:15 +0000</pubDate><guid>https://caiustheory.com/sending-array-elements-as-individual-arguments-in-ruby/</guid><description>&lt;p>Lets imagine we&amp;rsquo;ve got an array of strings, and we want to print it out as a list of strings using printf. &lt;em>(If you&amp;rsquo;re complaining about my logic here, hold fire for just a second good sir/madam.)&lt;/em>&lt;/p>
&lt;p>So we start off with the array of strings, and then pass it to printf with the right amount of &lt;code>%s&lt;/code>&amp;rsquo;s in the format string:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">arr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;two&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;three&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">printf&lt;/span> &lt;span class="s2">&amp;#34;%s, %s, %s&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">arr&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ~&amp;gt; -:3:in `printf&amp;#39;: too few arguments (ArgumentError)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ~&amp;gt; from -:3&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Oh whoops, we&amp;rsquo;ve actually only passed &lt;code>&amp;quot;%s, %s, %s&amp;quot;, [&amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, &amp;quot;three&amp;quot;]&lt;/code> to printf. So of course it whinges about not getting enough arguments. Now how do we fix this, how &lt;strong>do&lt;/strong> we pass an array with each element a seperate argument to a method?&lt;/p>
&lt;p>We use the &lt;code>*&lt;/code> of course! Just prefix the variable name with &lt;code>*&lt;/code> and the method is passed each element as separate arguments, rather than the whole array as one arguement.&lt;/p>
&lt;p>Going back to our &lt;code>printf&lt;/code> example above, we simply insert one character &lt;em>(the lowly &lt;code>*&lt;/code>)&lt;/em> and end up with a string being outputted.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">printf&lt;/span> &lt;span class="s2">&amp;#34;%s, %s, %s&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">arr&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; one, two, three&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now I realise this is a partially stupid example, but it serves to explain the point I wanted to make. If you were complaining about my choice of printf earlier, here is the way I think most rubyists would solve this problem instead.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">arr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;two&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;three&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; one two three&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And if I wanted to be slightly cleverer with the &lt;code>printf&lt;/code> version, and print out an array containing an unknown number of strings, but of a set width, then I could do the following. &lt;em>(NB: This is actually how I ran into this problem.)&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">arr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;two&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;three&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">printf&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="s2">&amp;#34;%6s&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">arr&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;gt;&amp;gt; one two three&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And that is where the lowly &lt;code>*&lt;/code> comes in.&lt;/p></description></item><item><title>Merry Testing</title><link>https://caiustheory.com/merry-testing/</link><pubDate>Thu, 25 Dec 2008 15:01:54 +0000</pubDate><guid>https://caiustheory.com/merry-testing/</guid><description>&lt;p>Just a few examples of the same test written in a few languages. Its testing setting the date on an object that is created in the tests&amp;rsquo; setup method already. These fall under the unit testing, rather than full-stack testing.&lt;/p>
&lt;h3 id="testing-in-objc-with-ocunithttpwwwsentechsoftwareocunit">Testing in ObjC with &lt;a href="http://www.sente.ch/software/ocunit/">OCUnit&lt;/a>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-objc" data-lang="objc">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Add a date and time
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="nf">testSettingDate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">NSDate&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">theDate&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">NSDate&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">STAssertNoThrow&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">calc&lt;/span> &lt;span class="nl">setDate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">theDate&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s">@&amp;#34;Shouldn&amp;#39;t raise an exception&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// And it should match when pulled out as well
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">STAssertEqualObjects&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">calc&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">theDate&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">@&amp;#34;%@ should match %@&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="n">calc&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">theDate&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="testing-in-ruby-using-rspechttprspecinfo">Testing in Ruby using &lt;a href="http://rspec.info/">RSpec&lt;/a>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="n">it&lt;/span> &lt;span class="s2">&amp;#34;should set the date successfully&amp;#34;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">the_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">today&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@calc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">the_date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># And it should match when pulled out as well&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@calc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">should&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">the_date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="testing-in-ruby-using-testunithttpwwwruby-docorgstdliblibdoctestunitrdocclassestestunithtml">Testing in Ruby using &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit&lt;/a>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_setting_date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">the_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">today&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@calc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">the_date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># And it should match when pulled out as well&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assert_equal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vi">@calc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">the_date&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="testing-in-php-using-phpunithttpphpunit">Testing in PHP using &lt;a href="http://phpun.it/">PHPUnit&lt;/a>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-php" data-lang="php">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> &lt;span class="nf">testSettingDate&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">date&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$calc&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="na">date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nv">$date&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># And it should match when pulled out as well
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nv">$this&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="na">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nv">$calc&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="na">date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$date&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Think Visibility: An Online Marketing Conference</title><link>https://caiustheory.com/think-visibility-an-online-marketing-conference/</link><pubDate>Sat, 20 Dec 2008 13:48:05 +0000</pubDate><guid>https://caiustheory.com/think-visibility-an-online-marketing-conference/</guid><description>&lt;p>Now I&amp;rsquo;m not one for blogging about events usually—if I&amp;rsquo;m attending one then I&amp;rsquo;ll just talk about it on &lt;a href="http://twitter.com/caius">twitter&lt;/a> quite a bit beforehand. However, seeing as this one is being organised by my housemate and I like to keep him in a good mood so he doesn&amp;rsquo;t do something daft like change the locks, I figured I&amp;rsquo;d blog about this one. &lt;em>(Also its really rather a good idea, I&amp;rsquo;ll be paying to attend and think he&amp;rsquo;s bloody mad to organise a conference!)&lt;/em>&lt;/p>
&lt;p>The conference is &lt;a href="http://www.thinkvisibility.com/">Think Visibility&lt;/a>, which is a&lt;/p>
&lt;blockquote>
&lt;p>one-day mini conference with a focus on the areas of web development and marketing which are usually left behind in the creation process: SEO, PPC, Monetisation, Blogging, Accessibility and Usability.&lt;/p>
&lt;/blockquote>
&lt;p>The &lt;a href="http://www.thinkvisibility.com/speakers.html">speaker line-up&lt;/a> has rather a lot of big names in it if you follow the SEO/Online marketing world, and its only £30 to turn up for the day and listen to them speak. Oh, and theres an afterparty with free drinks &lt;em>(Sponsor permitting)&lt;/em> where you can get drunk with your hero&amp;rsquo;s. (Or something.)&lt;/p>
&lt;p>Me, I&amp;rsquo;m attending simply because up until a year or so ago I thought SEO was a complete heap of crap, but having known &lt;a href="http://www.thehodge.co.uk/">Dom&lt;/a> for a while, and worked for an SEO agency, I&amp;rsquo;m starting to appreciate that there is an art to it, and it is a much needed skill to run a successful website.&lt;/p></description></item><item><title>Fix Mail.app crashing after 10.5.6 upgrade</title><link>https://caiustheory.com/fix-mailapp-crashing-after-1056-upgrade/</link><pubDate>Wed, 17 Dec 2008 13:58:04 +0000</pubDate><guid>https://caiustheory.com/fix-mailapp-crashing-after-1056-upgrade/</guid><description>&lt;p>When you upgrade to Mac OS 10.5.6, Mail.app might start crashing a few seconds after starting due to the GPG Bundle.&lt;/p>
&lt;p>The solution is to grab the updated version of the &lt;a href="http://www.sente.ch/software/GPGMail/English.lproj/GPGMail.html">GPG bundle&lt;/a> – &lt;a href="http://www.sente.ch/pub/beta/GPGMail_d55_Leopard.dmg">GPGMail_d55_Leopard.dmg&lt;/a>&lt;/p></description></item><item><title>Quick Picture of Yourself</title><link>https://caiustheory.com/quick-picture-of-yourself/</link><pubDate>Tue, 16 Dec 2008 18:12:53 +0000</pubDate><guid>https://caiustheory.com/quick-picture-of-yourself/</guid><description>&lt;p>Theres a meme going round the &lt;a href="http://www.google.com/search?q=Take+a+picture+of+yourself+right+now">blogosphere&lt;/a>/&lt;a href="http://search.twitter.com/search?q=Take+a+picture+of+yourself+right+now">twitterverse&lt;/a> recently, so I figured I&amp;rsquo;d jump on it because there aren&amp;rsquo;t any pictures of me on this blog yet. And there aren&amp;rsquo;t that many in my &lt;a href="http://flickr.com/photos/caius/">flickr&lt;/a> photostream either actually.&lt;/p>
&lt;p>&lt;img src="http://caius.name/images/qs/Me.png" alt="Picture of Caius" title="Caius Durling">&lt;/p>
&lt;p>&lt;em>&lt;a href="http://caius.name/images/qs/Me.png">Fullsize Picture&lt;/a>&lt;/em>&lt;/p>
&lt;h2 id="instructions">Instructions&lt;/h2>
&lt;ol>
&lt;li>Take a picture of yourself right now.&lt;/li>
&lt;li>Don’t change your clothes, don’t fix your hair… just take a picture.&lt;/li>
&lt;li>Post that picture with NO editing.&lt;/li>
&lt;li>Post these instructions with your picture.&lt;/li>
&lt;/ol></description></item><item><title>Installing Ubuntu on an iMac G3</title><link>https://caiustheory.com/installing-ubuntu-on-an-imac-g3/</link><pubDate>Tue, 09 Dec 2008 08:51:48 +0000</pubDate><guid>https://caiustheory.com/installing-ubuntu-on-an-imac-g3/</guid><description>&lt;p>I decided to install ubuntu onto my iMac G3&lt;!-- raw HTML omitted -->450Mhz G3, 768mb ram, 20GB Hard Drive&lt;!-- raw HTML omitted --> to play around with. Only problem was it would boot so far, then just stop at a black screen. In googling the fix, the blog post that contains the fix is &lt;em>slightly&lt;/em> outdated and 100% 404.&lt;/p>
&lt;p>Here is the fix, updated for Ubuntu 6.10 Desktop PPC:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>When the screen goes black, drop to the console&lt;/p>
&lt;pre>&lt;code> Control - Option - F2
&lt;/code>&lt;/pre>
&lt;p>&lt;em>(if you need to log in use the name ubuntu to log in.)&lt;/em>&lt;/p>
&lt;pre>&lt;code> $ sudo nano /etc/X11/xorg.conf
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Change the frequencies in monitor section as follows:&lt;/p>
&lt;pre>&lt;code> Section “Monitor”
Identifier “Generic Monitor”
Option “DPMS”
HorizSync 60-60
VertRefresh 43-117
EndSection
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>After the changes then type &lt;code>control-o&lt;/code>, &lt;code>return&lt;/code> (to accept the filename), then &lt;code>control-x&lt;/code> (save and exit nano)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Restart X by running the following:&lt;/p>
&lt;pre>&lt;code> sudo killall gdm &amp;amp;&amp;amp; sudo /etc/init.d/gdm start
&lt;/code>&lt;/pre>
&lt;/li>
&lt;/ol></description></item><item><title>About</title><link>https://caiustheory.com/about/</link><pubDate>Sun, 07 Dec 2008 04:09:28 +0000</pubDate><guid>https://caiustheory.com/about/</guid><description>&lt;h2 id="the-domain-name">The Domain Name&lt;/h2>
&lt;p>This blog used to be located at &lt;a href="http://swedishcampground.com/">SwedishCampground.com&lt;/a>, but I ended up with a better use for that name, so this got sidelined over here. I bought &lt;a href="http://caiustheory.com/">CaiusTheory.com&lt;/a> after having someone mention it to me in parody of Chaos Theory, and decided it was fairly apt for my musings and technical waffling.&lt;/p>
&lt;h2 id="the-author">The Author&lt;/h2>
&lt;p>I&amp;rsquo;m a:&lt;/p>
&lt;ul>
&lt;li>Mac User&lt;/li>
&lt;li>Developer at &lt;a href="http://freeagent.com/">FreeAgent&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://twitter.com/caius">Twitter Addict&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Find out more about me over on my &lt;a href="http://caius.name/">profile site&lt;/a>.&lt;/p></description></item><item><title>When work just feels right</title><link>https://caiustheory.com/when-work-just-feels-right/</link><pubDate>Fri, 21 Nov 2008 11:51:08 +0000</pubDate><guid>https://caiustheory.com/when-work-just-feels-right/</guid><description>&lt;p>Much like &lt;a href="http://www.3hv.co.uk/" title="3hv">Rahoul&amp;rsquo;s&lt;/a> post on &lt;a href="http://www.3hv.co.uk/blog/2008/10/16/working-for-brightbox/" title="Working for Brightbox">knowing you&amp;rsquo;re on the right path&lt;/a>, I had that moment this morning whilst we were discussing a future feature for our control panel.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>john&lt;/strong>: will I be able to superpoke our customers?&lt;br>
&lt;strong>john&lt;/strong>: is that in the spec?&lt;br>
&lt;strong>Jeremy&lt;/strong>: &amp;ldquo;John made server10 a zombie&amp;rdquo;&lt;br>
&lt;strong>Caius&lt;/strong>: &amp;ldquo;server10 zombified server9&amp;rdquo;&lt;br>
&lt;strong>Jeremy&lt;/strong>: &amp;ldquo;David has poked server19 19234 times&amp;rdquo;&lt;br>
&lt;strong>john&lt;/strong>: server16 messaged David &amp;ldquo;My disk is filling up and I have files I need to put somewhere, please help!&amp;rdquo;&lt;br>
&lt;strong>Caius&lt;/strong>: &amp;ldquo;Rahoul ended his friendship with server15&amp;rdquo;&lt;br>
&lt;strong>David&lt;/strong>: &amp;ldquo;server02 is now married to server05&amp;rdquo;&lt;br>
&lt;strong>Rahoul&lt;/strong>: server10 has sent you 12 videos of a fat man eating a cake&lt;br>
&lt;strong>David&lt;/strong>: server11 joined the group &amp;ldquo;KVM ftw&amp;rdquo;&lt;br>
&lt;strong>Caius&lt;/strong>: &amp;ldquo;server16 threw a sheep at server15&amp;rdquo;&lt;br>
&lt;strong>john&lt;/strong>: server03 joined the group &amp;ldquo;Centos sucks!&amp;rdquo;&lt;br>
&lt;strong>Caius&lt;/strong>: &amp;ldquo;server15 sent an emergency broadcast: physical movement detected&amp;rdquo;&lt;br>
&lt;strong>john&lt;/strong>: storage03 has logged off&lt;br>
&lt;strong>Caius&lt;/strong>: &amp;ldquo;x13 flew to the moon 0 times&amp;rdquo;&lt;br>
&lt;strong>john&lt;/strong>: disk5 in storage02 is now a zombie&lt;br>
&lt;strong>Jeremy&lt;/strong>: disk4 in storage02 is now a zombie&lt;br>
&lt;strong>Jeremy&lt;/strong>: disk3 in storage02 is now a zombie&lt;br>
&lt;strong>Jeremy&lt;/strong>: disk2 in storage02 is now a zombie&lt;br>
&lt;strong>john&lt;/strong>: storage02 was sold on ebay by Jeremy&lt;br>
&lt;strong>Caius&lt;/strong>: &amp;ldquo;john was sold on brightbox marketplace by storage5&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;p>&lt;em>(In case you don&amp;rsquo;t know, I work for &lt;a href="http://www.brightbox.co.uk/">Brightbox&lt;/a>.)&lt;/em>&lt;/p></description></item><item><title>Adding a remote to existing git repo</title><link>https://caiustheory.com/adding-a-remote-to-existing-git-repo/</link><pubDate>Sun, 09 Nov 2008 18:32:55 +0000</pubDate><guid>https://caiustheory.com/adding-a-remote-to-existing-git-repo/</guid><description>&lt;p>Usually for me this happens when I have an existing project and I setup a &lt;a href="http://github.com/">github&lt;/a> repo for it. As part of the setup for the github project, it gives you the commands to run to add the github repo as a remote to my local git repo.&lt;/p>
&lt;pre>&lt;code>cd existing_git_repo
git remote add origin git@github.com:caius/foo.git
git push origin master
&lt;/code>&lt;/pre>
&lt;p>The problem then is you&amp;rsquo;ve added the remote account, but the local master branch isn&amp;rsquo;t tracking the remote master branch, so when you try and just &lt;code>git pull&lt;/code> it will fail with a message telling you to set the remote refs up.&lt;/p>
&lt;pre>&lt;code>$ git pull
You asked me to pull without telling me which branch you
want to merge with, and 'branch.master.merge' in
your configuration file does not tell me either. Please
name which branch you want to merge on the command line and
try again (e.g. 'git pull &amp;lt;repository&amp;gt; &amp;lt;refspec&amp;gt;').
See git-pull(1) for details on the refspec.
If you often merge with the same branch, you may want to
configure the following variables in your configuration
file:
branch.master.remote = &amp;lt;nickname&amp;gt;
branch.master.merge = &amp;lt;remote-ref&amp;gt;
remote.&amp;lt;nickname&amp;gt;.url = &amp;lt;url&amp;gt;
remote.&amp;lt;nickname&amp;gt;.fetch = &amp;lt;refspec&amp;gt;
See git-config(1) for details.
&lt;/code>&lt;/pre>
&lt;p>The answer is to do what it says funnily enough, and add the remote refs tracking to the config file. The easiest way I&amp;rsquo;ve found of doing this is to edit &lt;code>.git/config&lt;/code> and add the following at the bottom of it.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="k">[branch &amp;#34;master&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">remote&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">origin
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> merge = refs/heads/master&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>Remember to change the branch or remote names if you need to.&lt;/em>&lt;/p>
&lt;p>Once you&amp;rsquo;ve added that to the config you can run &lt;code>git pull&lt;/code> on the master branch and it&amp;rsquo;ll do the usual automagical thing and pull the remote master branch changes into the local one!&lt;/p>
&lt;h4 id="updated-2008-11-09">Updated 2008-11-09&lt;/h4>
&lt;p>See CiarÃƒÂ¡n&amp;rsquo;s comment below for an all-inclusive command to do the above.&lt;/p></description></item><item><title>Removing non-existent source from rubygems</title><link>https://caiustheory.com/removing-non-existant-source-from-rubygems/</link><pubDate>Fri, 07 Nov 2008 06:08:28 +0000</pubDate><guid>https://caiustheory.com/removing-non-existant-source-from-rubygems/</guid><description>&lt;p>I just came to move some ruby scripts onto my mac mini, and to do so I needed to install a couple of gems. Now I realised I hadn&amp;rsquo;t installed or updated rubygems on the machine for a while, so I figured it was best to update &lt;code>gem&lt;/code> before installing the gems I wanted. Easier said than done.&lt;/p>
&lt;p>At some point in the past I had added &lt;code>http://gems.datamapper.org&lt;/code> as a source to rubygems. Since then the datamapper project has discontinued using this gem source to serve up gems, so I was getting the following output:&lt;/p>
&lt;pre>&lt;code>mm:daemons caius$ sudo gem update --system
Updating installed gems
Bulk updating Gem source index for: http://gems.rubyforge.org/
ERROR: While executing gem ... (Gem::RemoteSourceException)
HTTP Response 404 fetching http://gems.datamapper.org/yaml
&lt;/code>&lt;/pre>
&lt;p>Eeek! I can&amp;rsquo;t update because the source no longer exists. So I figured I&amp;rsquo;d remove the source before updating, that should work right? Wrong. It updates the sources before removing the source from the config it would appear.&lt;/p>
&lt;pre>&lt;code>mm:daemons caius$ sudo gem sources
** CURRENT SOURCES ***
http://gems.rubyforge.org
http://gems.datamapper.org
mm:daemons caius$ sudo gem sources -r http://gems.datamapper.org
Bulk updating Gem source index for: http://gems.rubyforge.org/
ERROR: While executing gem ... (Gem::RemoteSourceException)
HTTP Response 404 fetching http://gems.datamapper.org/yaml
&lt;/code>&lt;/pre>
&lt;p>Oh balls. So how do I remove the source without updating it first. I need to update it to remove it, but to remove it I need to update from it. Gotta love catch 22s!&lt;/p>
&lt;p>I remembered that &lt;code>gem install&lt;/code> has an option not to update sources, &lt;code>--no-update-sources&lt;/code>. So I figured thats gotta work when removing a source as well, but it doesn&amp;rsquo;t.&lt;/p>
&lt;pre>&lt;code>mm:daemons caius$ sudo gem sources -r http://gems.datamapper.org --no-update-sources
ERROR: While executing gem ... (OptionParser::InvalidOption)
invalid option: --no-update-sources
&lt;/code>&lt;/pre>
&lt;p>Oh crap. Now what do I do? Take my usual tactic and google for a hint of course! I&amp;rsquo;d considered trying to find where the gem config was and remove the source by hand, but I figured that wouldn&amp;rsquo;t be that simple. After hitting a couple of sites that weren&amp;rsquo;t relevant I ended up &lt;a href="http://jaigouk.blogspot.com/2008/07/404-fetching-httpgemsdatamapperorgyaml.html">on the edge of complexity&lt;/a> where he mentions the command &lt;code>nano ~/.gemrc&lt;/code>. Which made me wonder if that file contains the sources.&lt;/p>
&lt;pre>&lt;code>mm:daemons caius$ cat ~/.gemrc
---
:update_sources: true
:verbose: true
:bulk_threshold: 1000
:sources:
- http://gems.rubyforge.org
- http://gems.datamapper.org
:backtrace: false
:benchmark: false
&lt;/code>&lt;/pre>
&lt;p>All I needed to do was remove the &lt;code>- http://gems.datamapper.org&lt;/code> line and &lt;em>poof&lt;/em>, &lt;code>gem&lt;/code> was working again. One quick &lt;code>gem update --system&lt;/code> later and I was upgraded from gem 1.1.1 to 1.3.1 and installing the gems I needed.&lt;/p></description></item><item><title>Setting up git with rails apps</title><link>https://caiustheory.com/setting-up-git-with-rails-apps/</link><pubDate>Thu, 06 Nov 2008 13:03:02 +0000</pubDate><guid>https://caiustheory.com/setting-up-git-with-rails-apps/</guid><description>&lt;p>When I create a new rails app, I&amp;rsquo;m constantly going back to another project and stealing the &lt;code>.gitignore&lt;/code> file from it to make sure that git doesn&amp;rsquo;t know about certain files rails either updates frequently, or stores machine-specific data in. The latter is generally just &lt;code>config/database.yml&lt;/code>, because I develop alongside my colleagues at &lt;a href="http://brightbox.co.uk/" title="Brightbox - Serious Rails Hosting">Brightbox&lt;/a> and we deploy via &lt;a href="http://www.capify.org/">capistrano&lt;/a>, we always put the &lt;code>database.yml&lt;/code> file in the shared directory on the server, so we each have our own version with our local credentials in it locally. And thus we don&amp;rsquo;t want it to be tracked by git.&lt;/p>
&lt;p>Here&amp;rsquo;s what I&amp;rsquo;ve collated from various sources over the few weeks I&amp;rsquo;ve been using git + rails everyday.&lt;/p>
&lt;h4 id="gitignore">.gitignore&lt;/h4>
&lt;pre>&lt;code>config/database.yml
log/*.log
tmp/*
# OS X only
.DS_Store
**/.DS_Store
&lt;/code>&lt;/pre>
&lt;p>Then to make sure &lt;code>log/&lt;/code> and &lt;code>tmp/&lt;/code> are tracked, convention is to add a blank &lt;code>.gitkeep&lt;/code> file in them.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">touch log/.gitkeep
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">touch tmp/.gitkeep
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Spanning Sync</title><link>https://caiustheory.com/spanning-sync/</link><pubDate>Mon, 03 Nov 2008 11:40:04 +0000</pubDate><guid>https://caiustheory.com/spanning-sync/</guid><description>&lt;p>So for &lt;a href="http://www.brightbox.co.uk" title="Brightbox - Serious rails hosting">work&lt;/a> I have to subscribe to a shared google calendar the company uses. Annoyingly this can&amp;rsquo;t be through my Google Apps account though, it has to be through my normal google account.&lt;/p>
&lt;p>Also annoying is the fact google doesn&amp;rsquo;t let me subscribe to my shared calendars without making them 100% public. Which means the shared private calendar work uses would have to be a &lt;em>public&lt;/em> shared calendar, which is obviously not going to happen. (Can&amp;rsquo;t have everyone knowing when the secret drinking parties are!)&lt;/p>
&lt;p>Thankfully, there is already a solution out there to this problem, and it comes in the form of a Preference Pane called &lt;a href="http://spanningsync.com/" title="Spanning Sync">SpanningSync&lt;/a> that syncs iCal to Google Calendar. All you need to do is install the prefpane and enter your google email/password (which is then safely secured in your keychain I believe.)&lt;/p>
&lt;p>What it does is stick an icon in the menubar, and then at a pre-defined (and customisable) interval, sync any new changes between the local iCal calendar and the remote shared calendar in your google acccount.&lt;/p>
&lt;p>Spanning Sync is only $25 to register for the year, but you can save yourself $5 by entering &lt;strong>6EMQAC&lt;/strong> as the spanning sync coupon code, or &lt;a href="http://spanningsync.com/?r=6EMQAC">clicking here&lt;/a>&lt;/p></description></item><item><title>Create a blank rails app including plugins</title><link>https://caiustheory.com/create-a-blank-rails-app-including-plugins/</link><pubDate>Mon, 03 Nov 2008 06:48:27 +0000</pubDate><guid>https://caiustheory.com/create-a-blank-rails-app-including-plugins/</guid><description>&lt;p>When I create a rails app from scratch I like to include certain plugins to help me write the app, such as the &lt;em>Rspec&lt;/em> testing framework instead of the built-in &lt;em>Test::Unit&lt;/em> and &lt;em>jQuery&lt;/em> instead of &lt;em>prototype&lt;/em>.&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://rspec.info/">Rspec&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://github.com/rahoulb/rspec-rails/wikis">Rspec-rails&lt;/a> &lt;em>(NB: I use &lt;a href="http://3hv.co.uk">rahoul&lt;/a>&amp;rsquo;s fork of rspec-rails)&lt;/em>&lt;/li>
&lt;li>&lt;a href="http://github.com/aslakhellesoy/cucumber/wikis">Cucumber&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://github.com/brynary/webrat/wikis">Webrat&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://ennerchi.com/projects/jrails">jRails&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://plugins.code.lukeredpath.co.uk/browser/demeters_revenge/trunk">Demeters Revenge&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>And here are the commands in the order I run them to create the blank app.&lt;/p>
&lt;pre>&lt;code># Create the rails app
cd ~/Sites/apps/
rails myapp
cd myapp
# Setup a git repo
git init
# Add all files and make the initial import
git add .
git commit -m &amp;quot;Initial Import&amp;quot;
# Add the plugins as git submodules
git submodule add git://github.com/dchelimsky/rspec.git vendor/plugins/rspec
git submodule add git://github.com/rahoulb/rspec-rails.git vendor/plugins/rspec-rails
git submodule add git://github.com/aslakhellesoy/cucumber.git vendor/plugins/cucumber
git submodule add git://github.com/brynary/webrat.git vendor/plugins/webrat
git submodule add git://github.com/caius/demeters_revenge.git vendor/plugins/demeters_revenge
# Commit the changes
git ci -am &amp;quot;Adding all needed submodules&amp;quot;
# Replace TestUnit with rspec
git rm -r test/
ruby script/generate rspec
# Replace stories with cucumber features
rm -rf stories/
ruby script/generate cucumber
# Add the changes to git
git add .
git ci -m &amp;quot;Committing initial rspec/cucumber files&amp;quot;
# Install jRails, we have to install it using script/plugin
# Remove existing javascript files
git rm public/javascripts/*
mkdir public/javascripts
# Add jrails
ruby script/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails
git add vendor/plugins/jrails/ public/javascripts
git ci -m &amp;quot;Adding jRails to replace Prototype&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>And now you have a blank app waiting for you to write using features for full stack testing, and rspec for testing model and controller code.&lt;/p>
&lt;h4 id="updated-2008-11-04">Updated 2008-11-04&lt;/h4>
&lt;p>Added demeters revenge and jRails plugins.&lt;/p>
&lt;h4 id="update-2008-11-05">Update 2008-11-05&lt;/h4>
&lt;p>I&amp;rsquo;ve also blogged the &lt;a href="http://swedishcampground.com/setting-up-git-with-rails-apps">.gitignore&lt;/a> file I use with rails apps as well. Usually add it into my apps before running &lt;code>git init&lt;/code>&lt;/p></description></item><item><title>Keyboards</title><link>https://caiustheory.com/keyboards/</link><pubDate>Tue, 14 Oct 2008 13:59:01 +0000</pubDate><guid>https://caiustheory.com/keyboards/</guid><description>&lt;p>Back in the day I swapped the keys on my 12&amp;quot; powerbook keyboard around to read &lt;code>macgenius&lt;/code> across the middle row.&lt;/p>
&lt;p>&lt;a href="http://www.flickr.com/photos/caius/2941719496/">&lt;img src="http://farm4.static.flickr.com/3213/2941719496_caf2a6a813_m.jpg" alt="Powerbook Keyboard">&lt;/a>&lt;/p>
&lt;p>I unearthed the picture, and figured, why not do it to my apple aluminium keyboard? So I found a &lt;a href="http://skeltoac.com/2007/10/22/apple-keyboard-aluminum-keycap-removal/">tutorial&lt;/a> from some other guy that&amp;rsquo;d done it, and dug out my penknife.&lt;/p>
&lt;p>&lt;a href="http://www.flickr.com/photos/caius/2938651260/">&lt;img src="http://farm4.static.flickr.com/3243/2938651260_915f42d92d_m.jpg" alt="External Keyboard">&lt;/a>&lt;/p>
&lt;p>After that I decided to rearrange the macbook internal keyboard as well. First I googled around to make sure lifting the keys was the same as doing it on the external keyboard (which it appeared to be), then I went ahead and rearranged them as well.&lt;/p>
&lt;p>&lt;a href="http://www.flickr.com/photos/caius/2940872039/">&lt;img src="http://farm4.static.flickr.com/3214/2940872039_164ee672ef_m.jpg" alt="Internal Keyboard &amp;ndash; Macgenius">&lt;/a>&lt;/p>
&lt;p>So whilst I was wondering what to do about it, my mother emailed me and suggested using &lt;code>ontherails&lt;/code> instead of &lt;code>macgenius&lt;/code>. So I did, and now the top row reads &lt;code>ontherails&lt;/code> on the macbooks&amp;rsquo; internal keyboard.&lt;/p>
&lt;p>&lt;a href="http://www.flickr.com/photos/caius/2941726222/">&lt;img src="http://farm4.static.flickr.com/3146/2941726222_67b2405a89_m.jpg" alt="Internal Keyboard &amp;ndash; Ontherails">&lt;/a>&lt;/p>
&lt;p>All pictures are licenced under &lt;a href="http://creativecommons.org/licenses/by/2.0/deed.en_GB">Creative Commons Attribution 2.0 Generic licence&lt;/a> and the above pictures, plus some &lt;em>in progress&lt;/em> shots, are available in my &lt;a href="http://www.flickr.com/photos/caius/sets/72157608015895484/">Keyboard Modifications&lt;/a> flickr set.&lt;/p></description></item><item><title>Alistapart Survey</title><link>https://caiustheory.com/alistapart-survey/</link><pubDate>Tue, 29 Jul 2008 14:47:24 +0000</pubDate><guid>https://caiustheory.com/alistapart-survey/</guid><description>&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p></description></item><item><title>Another Concise Code Example</title><link>https://caiustheory.com/another-concise-code-example/</link><pubDate>Sat, 26 Apr 2008 15:54:09 +0000</pubDate><guid>https://caiustheory.com/another-concise-code-example/</guid><description>&lt;p>This is just another example showing how I refactor code down to its bare minimum. The reason why I do this so much (and indeed I think why ruby is so easy to read compared to other languages) is because it makes my code more readable and less of a bugger to pick up after a while.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Page&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kp">attr_accessor&lt;/span> &lt;span class="ss">:parent_id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">old_parent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parent?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">Page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="nb">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parent_id&lt;/span> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kp">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">parent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="no">Page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="nb">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parent_id&lt;/span> &lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="nb">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parent?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kp">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>old_parent&lt;/code> and &lt;code>parent&lt;/code> return exactly the same, but one is 2 lines compared to 5 and easier to read.&lt;/p>
&lt;p>&lt;strong>Update:&lt;/strong> &lt;a href="http://ciaranwal.sh/">Ciaran&lt;/a> pointed out that the Page.parent method would only ever return false. Added the return statement to it to fix the bug.&lt;/p></description></item><item><title>Inaugural Habaricon</title><link>https://caiustheory.com/inaugural-habaricon/</link><pubDate>Tue, 01 Apr 2008 07:27:55 +0000</pubDate><guid>https://caiustheory.com/inaugural-habaricon/</guid><description>&lt;p>So I managed to secure a place to &lt;a href="http://habaricon.com/">HabariCon &amp;lsquo;08&lt;/a>. Not quite sure what to expect, but being able to meet other people in real life and talk about habari &amp;amp; related things all day will be quite cool.&lt;/p>
&lt;p>Expect a round-up post of the &amp;lsquo;con tonight!&lt;/p></description></item><item><title>BarCamp Manchester</title><link>https://caiustheory.com/barcamp-manchester/</link><pubDate>Sat, 01 Mar 2008 11:34:25 +0000</pubDate><guid>https://caiustheory.com/barcamp-manchester/</guid><description>&lt;p>So I&amp;rsquo;m at BarCamp Manchester for the day. Its great meeting people I already know, and meeting new ones; most impressed by &lt;a href="http://petercooper.co.uk/">Peter&lt;/a>&amp;rsquo;s ruby shoes.. they glitter!&lt;/p>
&lt;p>So heres a little list of links for the day:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://www.flickr.com/photos/tags/BarCampManchesterUk/">http://www.flickr.com/photos/tags/BarCampManchesterUk/&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://barcamp.org/BarCampManchesterUk">http://barcamp.org/BarCampManchesterUk&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Command line tricks: Scripting Languages</title><link>https://caiustheory.com/command-line-tricks--scripting-languages/</link><pubDate>Thu, 14 Feb 2008 16:24:27 +0000</pubDate><guid>https://caiustheory.com/command-line-tricks--scripting-languages/</guid><description>&lt;p>To search your php.ini file quickly and easily with the option to use regular expressions, I tend to drop back to the &lt;!-- raw HTML omitted -->cli&lt;!-- raw HTML omitted -->. The reason for this is I can easily parse the output of &lt;code>phpinfo()&lt;/code> with &lt;code>grep&lt;/code>, and can do various things with the output, could even pass it to a script if I really wanted to.&lt;/p>
&lt;p>Here is the line I use to search &lt;code>phpinfo()&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;?php phpinfo() ?&amp;gt;&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> php &lt;span class="p">|&lt;/span> grep -i &lt;span class="nv">$search_string&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It passes the string through the php interpreter and then searches through it with grep.&lt;/p>
&lt;p>You can also do other nifty things with the shell &amp;amp; php + ruby especially (though I imagine python &amp;amp; perl work in the same way.) For instance I wanted to see if the following ruby would return the number of seconds since the &lt;a href="http:/en.wikipedia.org/wiki/Unix_Time">epoch&lt;/a> till now.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">puts&lt;/span> &lt;span class="no">Time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_i&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now I could fire up a PHP page and do something like the following&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-php" data-lang="php">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;?&lt;/span>&lt;span class="nx">php&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">echo&lt;/span> &lt;span class="s2">&amp;#34;php: &amp;#34;&lt;/span> &lt;span class="o">.&lt;/span> &lt;span class="nx">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">.&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">echo&lt;/span> &lt;span class="s2">&amp;#34;ruby: &amp;#34;&lt;/span> &lt;span class="o">.&lt;/span> &lt;span class="sb">`ruby -e &amp;#39;print Time.now.to_i&amp;#39;`&lt;/span> &lt;span class="o">.&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">?&amp;gt;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But what if I&amp;rsquo;ve not got a web server with PHP running on the machine I&amp;rsquo;m using? Well then I could drop back to the shell and run it through &lt;code>php&lt;/code> using &lt;code>cat&lt;/code> as a way to insert multiple lines, and it would look like the following&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">cat &lt;span class="s">&amp;lt;&amp;lt;PHP | php
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">&amp;lt;?php
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;php: &amp;#34; . time() . &amp;#34;\n&amp;#34;;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;ruby: &amp;#34; . `ruby -e &amp;#39;print Time.now.to_i&amp;#39;` . &amp;#34;\n&amp;#34;;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">PHP&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">php: &lt;span class="m">1203004463&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ruby: &lt;span class="m">1203004463&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now this works, but why do I want to remember all that php, and seeing as I have to drop back to the shell to access the ruby statement, why not just let the shell do all the work? So after a few seconds thinking, I came up with this&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">ruby -e &lt;span class="s1">&amp;#39;puts &amp;#34;ruby: #{Time.now.to_i}&amp;#34;&amp;#39;&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;&amp;lt;?php echo &amp;#34;PHP: &amp;#34; . time() . &amp;#34;\n&amp;#34; ?&amp;gt;&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> php
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This runs the ruby code through &lt;code>ruby&lt;/code> and the php code through &lt;code>php&lt;/code> without dropping back to the shell from within a language interpreter :)&lt;/p>
&lt;h3 id="update">Update:&lt;/h3>
&lt;p>Fangel pointed out &lt;code>php -r&lt;/code> is the equivilent of &lt;code>ruby -e&lt;/code> so the final commands could just be:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">ruby -e &lt;span class="s1">&amp;#39;puts &amp;#34;ruby: #{Time.now.to_i}&amp;#34;&amp;#39;&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>php -r &lt;span class="s1">&amp;#39;echo &amp;#34;PHP: &amp;#34;.time().&amp;#34;\n&amp;#34;;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Refactoring code logically</title><link>https://caiustheory.com/refactoring-code-logically/</link><pubDate>Tue, 12 Feb 2008 12:28:38 +0000</pubDate><guid>https://caiustheory.com/refactoring-code-logically/</guid><description>&lt;p>And now an example of how I write my ruby code and get it down to the bare, readable, minimum code needed. This is real life code taken from a website I&amp;rsquo;m building, but I&amp;rsquo;ve changed the objects to a blog post because more people will relate to that easier.&lt;/p>
&lt;p>The show object has an id passed in using the &lt;code>params&lt;/code> Hash, I want to check if that post exists in the database first. If it does, then render the page, and if it doesn&amp;rsquo;t return a 404 error page.&lt;/p>
&lt;p>So I start off by writing this in &lt;em>longhand&lt;/em> ruby, I&amp;rsquo;m using the &lt;a href="http://merbivore.com/">merb&lt;/a> framework with &lt;a href="http://datamapper.com/">DataMapper&lt;/a> ORM by the way.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">show&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="vi">@post&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="vi">@post&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="s2">&amp;#34;404 - Not found&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now whilst theres nothing wrong with this code, it just doesn&amp;rsquo;t look right to me. There is a big if/else statement in there whilst I&amp;rsquo;m sure there doesn&amp;rsquo;t need to be.&lt;/p>
&lt;p>Now I know if I return at any point in a ruby method, it exits the method at that point. So the first thing to is to refactor the &lt;code>if&lt;/code> test to remove a line of code. I shall assign &lt;code>@post&lt;/code> to the result of the DB as the actual if statement&amp;rsquo;s test.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">show&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="vi">@post&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="s2">&amp;#34;404 - Not found&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So thats reading slightly better, and also is a line less of code. Now I wonder if I can use a &lt;code>return true&lt;/code> in there to stop me having to explicitly state an &lt;code>else&lt;/code> clause.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">show&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="vi">@post&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kp">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="s2">&amp;#34;404 - Not found&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now the eagerest amongst you will be wondering what the advantage of that code is. It doesn&amp;rsquo;t appear any more readable (slightly less in fact as you have to figure out its an implicit else) and is exactly the same amount of lines as the previous example. But what if we change the &lt;code>if&lt;/code> to an &lt;code>if !&lt;/code> and flip the code logic around?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">show&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">!&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="vi">@post&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="s2">&amp;#34;404 - not found&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now a raise will stop the code executing, and in the real application you would in fact just redirect to your 404 error page. The problem now is the &lt;code>if !&lt;/code> looks ugly and isn&amp;rsquo;t easily readable.&lt;/p>
&lt;p>All &lt;code>unless&lt;/code> does is &lt;code>if !&lt;/code>, that is, if the inverse of the result of the test statement is true, then invoke the block given to it. A quick example for you:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># without unless&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="vi">@user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">logged_in?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Please login.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># using unless&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">unless&lt;/span> &lt;span class="vi">@user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">logged_in?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Please login.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now whilst &lt;code>if !&lt;/code> doesn&amp;rsquo;t seem that bad compared to &lt;code>unless&lt;/code>, the readablility of the code increases. It reads more as a flow of logic, and is quicker for the human brain to walk through (my brain anyway!)&lt;/p>
&lt;p>So using unless we get 4 lines of code that is easily readable.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">show&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">unless&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="vi">@post&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="s2">&amp;#34;404 - Not found&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now what if we go one step further and use the unless shorthand way of testing and exectuting one line of code?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">show&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="s2">&amp;#34;404 - Not found&amp;#34;&lt;/span> &lt;span class="k">unless&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="vi">@post&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Post&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="ss">:id&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">render&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And that is generally how I write my code logically. Of course for something simple like this I&amp;rsquo;d probably jump in at the last block having refactored it in my head first, but for more complex things I tend to write them exlicitly and then refactor them down whilst maintaining readability of my code.&lt;/p></description></item><item><title>Use datamapper sessions with merb &amp; datamapper</title><link>https://caiustheory.com/use-datamapper-sessions-with-merb-datamapper/</link><pubDate>Tue, 05 Feb 2008 20:27:31 +0000</pubDate><guid>https://caiustheory.com/use-datamapper-sessions-with-merb-datamapper/</guid><description>&lt;h3 id="issue">Issue&lt;/h3>
&lt;p>Can&amp;rsquo;t use merb sessions with datamapper &amp;amp; mysql, get back an error about needing an id on the text column or something (I had the error a couple of days ago.)&lt;/p>
&lt;h3 id="solution">Solution&lt;/h3>
&lt;p>I suggest grabbing merb_datamapper svn source to fix this in. To do so make sure you have subversion installed on your machine (I&amp;rsquo;m assuming a Unix based machine here.)&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Checkout the source&lt;/p>
&lt;pre>&lt;code> svn co http://svn.devjavu.com/merb/plugins/merb_datamapper
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Open up the affected file in your favourite editor &lt;em>(I use TextMate)&lt;/em>&lt;/p>
&lt;pre>&lt;code> cd merb_datamapper
mate lib/merb/sessions/data_mapper_session.rb
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Find line 25 that contains&lt;/p>
&lt;pre>&lt;code> `property :session_id, :text, :lazy =&amp;gt; false, :key =&amp;gt; true`
&lt;/code>&lt;/pre>
&lt;p>and remove &lt;code>:text, :lazy =&amp;gt; false&lt;/code> to replace it with &lt;code>:string&lt;/code>&lt;/p>
&lt;pre>&lt;code> `property :session_id, :string, :key =&amp;gt; true`
&lt;/code>&lt;/pre>
&lt;p>Save and close the file, thats the editing done. Now to install the gem.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Build the gem&lt;/p>
&lt;pre>&lt;code> rake gem
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>Install the gem&lt;/p>
&lt;pre>&lt;code> sudo gem install pkg/merb_datamapper-0.5.gem
&lt;/code>&lt;/pre>
&lt;/li>
&lt;/ol>
&lt;p>And you&amp;rsquo;re away with the fix installed. Now just run &lt;code>merb&lt;/code> to create your sessions table in the db. Hope this helped!&lt;/p></description></item><item><title>Why do I love Ruby?</title><link>https://caiustheory.com/why-do-i-love-ruby/</link><pubDate>Wed, 30 Jan 2008 14:15:24 +0000</pubDate><guid>https://caiustheory.com/why-do-i-love-ruby/</guid><description>&lt;p>So mother (who can&amp;rsquo;t program) just posed me the question&lt;/p>
&lt;blockquote>
&lt;p>Why is Ruby your favourite programming language?&lt;/p>
&lt;/blockquote>
&lt;p>Me being a show off jumped straight into &lt;a href="http://macromates.com/">TextMate&lt;/a> and banged out some code in real time to show her. First up, a quick little one-liner of Ruby code to output a String:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Hello World&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; &amp;#34;Hello World&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So she goes, &amp;ldquo;Sure, but whats so brilliant about that?&amp;rdquo; So I just decide to reverse the string, have it output in reverse order:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Hello World&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">reverse&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># =&amp;gt; &amp;#34;dlroW olleH&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then the next question comes, &amp;ldquo;So what makes that so much easier than in other languages?&amp;rdquo; Well now I was thinking on the spot about which other language I can bang out a quick example in without having to look up too much information. PHP seems the logical choice, being the language I know best behind Ruby.&lt;/p>
&lt;p>Thinking about how to do it in PHP, I can&amp;rsquo;t think of a function to reverse the content of a string, but I know that &lt;code>array_reverse()&lt;/code> exists, so I just split it into an array and reverse that array. Only problem is I can&amp;rsquo;t remember how to split a string by &lt;code>&amp;quot;&amp;quot;&lt;/code>, I don&amp;rsquo;t think &lt;code>explode( &amp;quot;&amp;quot;, $var )&lt;/code> does the job. So I quickly jump in and write the following code to test my concern.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-php" data-lang="php">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;?&lt;/span>&lt;span class="nx">php&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello World&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">explode&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$a&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">array_reverse&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="nv">$b&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">echo&lt;/span> &lt;span class="nx">implode&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$c&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">?&amp;gt;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err"># =&amp;gt; ERROR
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The reason for the error is because I&amp;rsquo;ve missed a semi colon off the end of line 2, to this I get the response, &amp;ldquo;well thats certainly not as nice as ruby.&amp;rdquo; Just because one little character is missing!&lt;/p>
&lt;p>So I fix the semi colon and run it again, now I get an error complaining about explode not being able to split by a missing delimiter (the empty string - &lt;code>&amp;quot;&amp;quot;&lt;/code>) So I go hunting through the &lt;a href="http://php.net/">php.net&lt;/a> docs and find &lt;code>str_split()&lt;/code>, which does exactly what I want it to.&lt;/p>
&lt;p>In replacing &lt;code>explode()&lt;/code> with &lt;code>str_split()&lt;/code> and running it via the &lt;code>php&lt;/code> command line binary, I realise that I haven&amp;rsquo;t got any &lt;code>\n&lt;/code> (newlines) at the end of it, so it doesn&amp;rsquo;t display nicely in the terminal. I thus update the script to the following and show her the result:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-php" data-lang="php">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;?&lt;/span>&lt;span class="nx">php&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello World&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">explode&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$a&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">array_reverse&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="nv">$b&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">echo&lt;/span> &lt;span class="nx">implode&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$c&lt;/span> &lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">?&amp;gt;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err"># =&amp;gt; &amp;#34;dlroW olleH&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And so she goes away seeing why I prefer Ruby to other languages for &lt;em>most&lt;/em> programming I do. There are things Ruby fails at (and don&amp;rsquo;t get me started on why rails isn&amp;rsquo;t going to replace php!) and other places where it succeeds very well.&lt;/p>
&lt;p>But each to their own, and my own favourite is Ruby!&lt;/p>
&lt;h3 id="update">Update&lt;/h3>
&lt;p>As pointed out in the comments, if I had looked a bit further I would&amp;rsquo;ve found &lt;code>strrev()&lt;/code> which does the same as the &lt;code>reverse&lt;/code> method in Ruby. So in fact the final code would be:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">puts&lt;/span> &lt;span class="s2">&amp;#34;Hello World&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">reverse&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>vs&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-php" data-lang="php">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;?&lt;/span>&lt;span class="nx">php&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">echo&lt;/span> &lt;span class="nx">strrev&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="s2">&amp;#34;Hello World&amp;#34;&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">?&amp;gt;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So it turns out this was a bad way to show why I prefer Ruby to PHP code wise to mother, think I might have to just bite the bullet and write about why I prefer &lt;code>object.method&lt;/code> to &lt;code>method( object )&lt;/code>!&lt;/p></description></item><item><title>UK Parking</title><link>https://caiustheory.com/uk-parking/</link><pubDate>Sat, 12 Jan 2008 12:35:01 +0000</pubDate><guid>https://caiustheory.com/uk-parking/</guid><description>&lt;p>So I just saw this in my twitter stream:&lt;/p>
&lt;blockquote>
&lt;p>&lt;a href="http://twitter.com/peterc/statuses/590099072">peterc&lt;/a>: Warning UK drivers.. councils get powers on March 31st to give you parking fines for infractions they see on CCTV!&lt;/p>
&lt;/blockquote>
&lt;p>This indeed sucks. We&amp;rsquo;ll see how successful they are at ticketing people and whether anyone abuses the system&amp;hellip;&lt;/p></description></item><item><title>Published Pictures</title><link>https://caiustheory.com/published-pictures/</link><pubDate>Sat, 05 Jan 2008 16:08:39 +0000</pubDate><guid>https://caiustheory.com/published-pictures/</guid><description>&lt;p>Interesting email arrived in my inbox today. I attended &lt;a href="http://barcamp.org/BarCampLeeds">BarCamp Leeds&lt;/a> in late 2007 and whilst I was there I happened to take some pictures (as I am apt to do these days.)&lt;/p>
&lt;p>Anyway, I was rather happy to see that at least one picture isn&amp;rsquo;t just stagnating in my &lt;a href="http://flickr.com/photos/caius/">flickr stream&lt;/a>:&lt;/p>
&lt;blockquote>
&lt;p>Hi Caius,&lt;/p>
&lt;p>I am delighted to let you know that one of your photos with&lt;br>
a Creative Commons license has been selected for inclusion&lt;br>
in the newly released fourth edition of our Schmap Leeds&lt;br>
Guide:&lt;/p>
&lt;p>Town Hall&lt;br>
&lt;a href="http://www.schmap.com/leeds/sights_hydepark/p=39139/i=39139_10.jpg">http://www.schmap.com/leeds/sights_hydepark/p=39139/i=39139_10.jpg&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;a href="">Original Picture on flickr&lt;/a>&lt;/p></description></item><item><title>Twitter Statistics</title><link>https://caiustheory.com/twitter-statistics/</link><pubDate>Wed, 02 Jan 2008 07:15:00 +0000</pubDate><guid>https://caiustheory.com/twitter-statistics/</guid><description>&lt;p>&lt;a href="http://flickr.com/photo_zoom.gne?id=2157771886&amp;amp;size=o">&lt;img src="http://farm3.static.flickr.com/2345/2157771886_9e41008ac2_m.jpg" alt="Twitter Statistics for caius">&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://dcortesi.com/2007/12/27/twitter-stats/">Just&lt;/a> &lt;a href="http://www.flickr.com/photos/gruber/2156085517/">joining&lt;/a> &lt;a href="http://www.randsinrepose.com/archives/2008/01/01/year_in_twitter.html">the&lt;/a> &lt;a href="http://kosmar.de/archives/2007/12/29/twitter-statistics/">band&lt;/a> &lt;a href="http://blog.nordquist.org/?p=2083">wagon&lt;/a> in posting up my twitter statistics. The skew towards december being the month I twitter most in is because I enabled twitter sms, and ended up replying/updating a lot more often than I expected.&lt;/p></description></item><item><title>OS X User has a virus</title><link>https://caiustheory.com/os-x-user-has-a-virus/</link><pubDate>Wed, 02 Jan 2008 01:15:15 +0000</pubDate><guid>https://caiustheory.com/os-x-user-has-a-virus/</guid><description>&lt;p>No not my computer, me. I&amp;rsquo;ve managed to pickup an &lt;!-- raw HTML omitted -->acute coryza&lt;!-- raw HTML omitted --> virus. It causes &lt;code>/dev/random&lt;/code> to constantly pass data to &lt;code>/Volumes/nose&lt;/code>. I don&amp;rsquo;t think I got this from reading email, but I&amp;rsquo;m pretty sure it was a windows user who passed it to me.&lt;/p>
&lt;p>If I flush my partitions to disk every now and then I can get by with a clean &lt;code>/Volumes/nose&lt;/code> for a while before &lt;code>/dev/random&lt;/code> starts clogging it up again.&lt;/p></description></item><item><title>dSLR Quote</title><link>https://caiustheory.com/dslr-quote/</link><pubDate>Mon, 31 Dec 2007 17:25:25 +0000</pubDate><guid>https://caiustheory.com/dslr-quote/</guid><description>&lt;p>I was just talking to &lt;a href="http://keihatsu.org/">Nadim&lt;/a> about him getting a new camera and then this happened:&lt;/p>
&lt;blockquote>
&lt;p>Nadim: &lt;a href="http://cyraq.deviantart.com/art/Above-the-Clouds-72170767">http://cyraq.deviantart.com/art/Above-the-Clouds-72170767&lt;/a>&lt;br>
Nadim: Did you see that?&lt;br>
Nadim: Taken couple of weeks ago&lt;br>
Caius: woa&lt;br>
Caius: and you need a new camera because? :P&lt;br>
Nadim: I have wet dreams about DSLR&amp;rsquo;s&lt;/p>
&lt;/blockquote></description></item><item><title>Quote to see the new year in</title><link>https://caiustheory.com/quote-to-see-the-new-year-in/</link><pubDate>Mon, 31 Dec 2007 17:11:11 +0000</pubDate><guid>https://caiustheory.com/quote-to-see-the-new-year-in/</guid><description>&lt;p>So I&amp;rsquo;m a geek, as my friends are gradually realising more and more. Anyway, I twitter a lot, and occasionally write quotes that need to be saved elsewhere. And what generally makes tweets funnier are other people replying to them.&lt;/p>
&lt;p>A little background information. This had just taken place in #habari (a chat room.)&lt;/p>
&lt;pre>&lt;code>&amp;lt;h0bbel&amp;gt; ringmaster: i'll show you my winky
* ringmaster runs.
&amp;lt;h0bbel&amp;gt; as jmullan has seen it
&amp;lt;h0bbel&amp;gt; i think
&amp;lt;jmullan&amp;gt; no, I didn't look
&amp;lt;ringmaster&amp;gt; 0_o
&amp;lt;h0bbel&amp;gt; i was kinda drunk at the time
&amp;lt;h0bbel&amp;gt; lol
&amp;lt;jmullan&amp;gt; we were playing &amp;quot;lightsabers&amp;quot; while peeing
&amp;lt;jmullan&amp;gt; not &amp;quot;swords&amp;quot;
&amp;lt;jmullan&amp;gt; I had the yellow saber, h0bbel had the green one
&amp;lt;jmullan&amp;gt; I'm not sure how that worked
&amp;lt;h0bbel&amp;gt; you said you didn't look!
&amp;lt;h0bbel&amp;gt; How did you know it was green?
&amp;lt;jmullan&amp;gt; I just saw the beam, not the handle, if you know what I'm saying
&amp;lt;h0bbel&amp;gt; ehehe
&amp;lt;Caius&amp;gt; xD
&amp;lt;ringmaster&amp;gt; This is all somewhat disturbing.
&lt;/code>&lt;/pre>
&lt;p>So in order&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="http://twitter.com/caius/statuses/549893582">me&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>man, #habari just wouldn&amp;rsquo;t be the same without the semi-homosexual discussions every now and then&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://twitter.com/caius/statuses/549893582">me&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>Formatting some SQL queries for a fellow dev&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://twitter.com/h0bbel/statuses/549895502">h0bbel&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>&lt;a href="http://twitter.com/caius/statuses/549893582">http://twitter.com/caius/st&amp;hellip;&lt;/a> is realy quoteworthy ;-)&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://twitter.com/tmertz/statuses/549899752">Mertz&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>@&lt;a href="http://twitter.com/caius">caius&lt;/a>, wtf are you doing? put down the computer, take five steps back and go find a new years celebration.&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://twitter.com/caius/statuses/549903292">me&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>@&lt;a href="http://twitter.com/tmertz">tmertz&lt;/a> just hanging in #habari whilst editing some SQL queries @&lt;a href="http://twitter.com/h0bbel">h0bbel&lt;/a> wrote waiting for 1900GMT to go round my mates and get drunk&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;/ul>
&lt;p>And on the back of that, I&amp;rsquo;d just like to say have a very merry new years eve and just follow your desires onwards in life!&lt;/p></description></item></channel></rss>