<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>I'm trying</title><link href="https://jimkubicek.com/" rel="alternate"></link><link href="https://jimkubicek.com/atom.xml" rel="self"></link><id>https://jimkubicek.com/</id><updated>2020-12-30T00:00:00-08:00</updated><entry><title>The Ember Cup</title><link href="https://jimkubicek.com/the-ember-cup.html" rel="alternate"></link><published>2020-12-30T00:00:00-08:00</published><updated>2020-12-30T00:00:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2020-12-30:/the-ember-cup.html</id><summary type="html">&lt;p&gt;Stephanie and I got matching &lt;a href="https://ember.com"&gt;Ember&lt;/a&gt; cups for Christmas. I’m generally happy with mine, but there are some things that folks should know to avoid frustration.&lt;/p&gt;
&lt;p&gt;First, here’s what this cup is &lt;em&gt;not:&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It’s not a way to warm up a chilled drink. It &lt;em&gt;can&lt;/em&gt; warm Chemex …&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;p&gt;Stephanie and I got matching &lt;a href="https://ember.com"&gt;Ember&lt;/a&gt; cups for Christmas. I’m generally happy with mine, but there are some things that folks should know to avoid frustration.&lt;/p&gt;
&lt;p&gt;First, here’s what this cup is &lt;em&gt;not:&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It’s not a way to warm up a chilled drink. It &lt;em&gt;can&lt;/em&gt; warm Chemex coffee that has been cooling on the counter, but it will take 60+ minutes and isn’t worth it. In fact, the heating elements won’t start the warming process until they detect warm liquids. If you want to pour some milk into your Ember to get a head start on warming it up, you’ll have to trigger the warming process from the phone app.&lt;/li&gt;
&lt;li&gt;It's not designed to keep a cup of coffee warm when away from the base station indefinitely. Maybe our house is colder than average or I like my coffee warmer then average, but the battery doesn’t last long enough to support an extended trip away from the charging base.  On a fully-charged battery I can easily drink one hot drink while sitting outside, but the battery will die pretty quickly into the second cup.&lt;/li&gt;
&lt;li&gt;The battery does &lt;em&gt;not&lt;/em&gt; quick charge. I haven’t timed how long it takes, but getting back up close to 100% isn’t a casual thing, you can't just throw it into the charging coaster for a few minutes to top up the battery. When you get the low-battery warning, you're going to need to leave it sitting there for at least 30 minutes to get a decent charge up and well over an hour to fully charge the battery.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This may sound like I’m kinda down on the cup, but that’s not the case! For my use case, it’s actually just fine. I bought this to sit at my office desk and keep my drink toasty while I ignore it for long periods of time. In this use case, I would have the charging base on my desk and the cup would be charging most of the time. If I want to work outside or in another room, I can have a hot drink for 45 minutes or so, which isn’t too bad.&lt;/p&gt;
&lt;p&gt;This cup replaces a &lt;a href="https://www.hydroflask.com/12-oz-coffee-mug"&gt;HydroFlask mug&lt;/a&gt; that I’ve been using. The HydroFlask is still expensive for a cup, but it's a lot cheaper than the ember and does do a pretty good job keeping drinks warm, but it’s got a few downsides. While it does a great job keeping drinks toasty, it doesn't keep them warm forever. Second, it’s a little too insulated; if you put boiling hot water in it, the water will be too hot to drink for a long time. The trick is to keep the the lid off for a while, until it hits drinkable temp and then slap the lid on to preserve the temperature. Get this timing wrong and you scald your mouth or end up with a lukewarm drink. Second, it’s a metal cup with a plastic lid, so it gets a bit of the weird travel-mug tastes. I don’t know what the Ember is made out of, but it doesn’t taste or smell any different then a ceramic mug. Also, since the Ember has no lid, it very quickly cools down to the perfect drinking temperature and stays there.&lt;/p&gt;
&lt;p&gt;Would I recommend that someone buy an Ember mug? Maybe? It’s $130, so it’s not a trivial purchase. If you get your coffee from a already-warmed source (i.e. not a cold Chemex) and you spend &lt;em&gt;most&lt;/em&gt; of your time drinking from a place where you can plug in a charging puck, then I’d consider it. &lt;/p&gt;
&lt;p&gt;If Ember releases a new model with a quick-charge mode and a robust heating element that can reheat my cold coffee in a reasonable amount of time, I would reccomend the cup with no reservations.&lt;/p&gt;</content><category term="Reviews"></category></entry><entry><title>I'm writing this on an iPad</title><link href="https://jimkubicek.com/im-writing-this-on-an-ipad.html" rel="alternate"></link><published>2020-04-27T00:00:00-07:00</published><updated>2020-04-27T00:00:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2020-04-27:/im-writing-this-on-an-ipad.html</id><content type="html">&lt;p&gt;Well, my last post was about how I have my whole deployment pipeline setup in Github, let's see if I can use it from an iPad to publish a post. I wonder if this will work?&lt;/p&gt;</content><category term="Writing"></category><category term="web"></category><category term="iPad"></category></entry><entry><title>Setting up Github Actions for Deploying Pelican</title><link href="https://jimkubicek.com/setting-up-github-actions-for-deploying-pelican.html" rel="alternate"></link><published>2019-12-18T00:00:00-08:00</published><updated>2019-12-18T00:00:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2019-12-18:/setting-up-github-actions-for-deploying-pelican.html</id><summary type="html">&lt;p&gt;Github actions allow me to implement continuous delivery for this blog. Each time I merge to master, &lt;a href="/"&gt;jimkubicek.com&lt;/a&gt; is built and deployed.&lt;/p&gt;
&lt;p&gt;First, this action should run anytime the &lt;code&gt;master&lt;/code&gt; branch is updated.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Deploy&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to create our deploy steps …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Github actions allow me to implement continuous delivery for this blog. Each time I merge to master, &lt;a href="/"&gt;jimkubicek.com&lt;/a&gt; is built and deployed.&lt;/p&gt;
&lt;p&gt;First, this action should run anytime the &lt;code&gt;master&lt;/code&gt; branch is updated.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Deploy&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to create our deploy steps. Let's use a Ubuntu container with the latest commit in our branch checked out.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Deploy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jimkubicek&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;com&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uses&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;checkout&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install Python 3.8 (or whatever version you're using):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.8&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="nv"&gt;@v1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.8&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Upgrade &lt;code&gt;pip&lt;/code&gt; and install the latest version of the &lt;a href="https://blog.getpelican.com"&gt;Pelican&lt;/a&gt; static site generator and the &lt;a href="http://www.pyinvoke.org"&gt;Invoke&lt;/a&gt; task runner:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pelican&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;upgrade&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;invoke&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pelican&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Markdown&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order for SSH to work correctly, we'll need to make sure that our public and private keys are created and placed in the correct location. On your local machine, let's generate a valid keypair.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssh-keygen -t rsa -f -b 4096 ./github_actions -C github_actions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, let's copy the public key up to our server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nv"&gt;@example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;github_actions&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now copy the private key into the pasteboard and add it to your github secrets. This action uses a secret with the name &lt;code&gt;PRIVATE_KEY&lt;/code&gt;. Paste the contents of your clipboard into this secret.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cat github_actions | pbcopy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, in our action file, we've got to read this secret and get it setup on disk. The &lt;code&gt;env&lt;/code&gt; command extracts the secret out and stores it into an environment variable. Make sure that the &lt;code&gt;.ssh&lt;/code&gt; directory exists, and save that private key into the &lt;code&gt;id_rsa&lt;/code&gt; file. SSH requires that the key has restricted access, so set the access to &lt;code&gt;400&lt;/code&gt;. Finally, add our IP address to the list of known and approved hosts. The downside of this is that if your server is MITM'd you'll continue to just blindly trust it. I'm not sure of a way around this, if you know, let me know.&lt;/p&gt;
&lt;p&gt;Here's the final SSH setup stage: &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    - name: Setup the SSH key
      env:
        PRIVATE_KEY: &lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PRIVATE_KEY&lt;/span&gt; &lt;span class="cp"&gt;}&lt;/span&gt;}
      run: |
        mkdir &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.ssh
        echo &amp;quot;&lt;span class="nv"&gt;$PRIVATE_KEY&lt;/span&gt;&amp;quot; &amp;gt;&amp;gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.ssh/id_rsa
        chmod 400 &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.ssh/id_rsa
        ssh-keyscan -t rsa &lt;span class="nt"&gt;&amp;lt;SERVER&lt;/span&gt;&lt;span class="err"&gt;_IP&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.ssh/known_hosts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, use Invoke to upload to our server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    - name: Push to example.com
      run: inv publish
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="development"></category><category term="web"></category><category term="Pelican"></category></entry><entry><title>Setting up Let's Encrypt with Nginx</title><link href="https://jimkubicek.com/setting-up-lets-encrypt-with-nginx.html" rel="alternate"></link><published>2019-12-13T00:00:00-08:00</published><updated>2019-12-13T00:00:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2019-12-13:/setting-up-lets-encrypt-with-nginx.html</id><summary type="html">&lt;p&gt;This blog is a static site generated with &lt;a href="https://docs.getpelican.com/en/stable/index.html"&gt;Pelican&lt;/a&gt;. It's now almost 2020, which means that using &lt;code&gt;https&lt;/code&gt; isn't just a good idea, it's pretty-much mandatory. The good news is that setting up Ubuntu, &lt;a href="https://www.nginx.com"&gt;Nginx&lt;/a&gt; and &lt;a href="https://letsencrypt.org"&gt;Let's Encrypt&lt;/a&gt; is incredibly straightforward. Start to finish it only took me a bit …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This blog is a static site generated with &lt;a href="https://docs.getpelican.com/en/stable/index.html"&gt;Pelican&lt;/a&gt;. It's now almost 2020, which means that using &lt;code&gt;https&lt;/code&gt; isn't just a good idea, it's pretty-much mandatory. The good news is that setting up Ubuntu, &lt;a href="https://www.nginx.com"&gt;Nginx&lt;/a&gt; and &lt;a href="https://letsencrypt.org"&gt;Let's Encrypt&lt;/a&gt; is incredibly straightforward. Start to finish it only took me a bit over an hour to get everything working together, which was far faster than I expected.&lt;/p&gt;
&lt;p&gt;These instructions are based off a walkthrough in &lt;a href="https://cloudsupport.digitalocean.com/s/"&gt;Digital Ocean's documentation&lt;/a&gt;, which inexplicable can't be directly linked to. &lt;em&gt;Update&lt;/em&gt; There are better instructions available on the &lt;a href="https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx"&gt;certbot&lt;/a&gt; page. You should probably follow those instructions. &lt;/p&gt;
&lt;p&gt;Before we get into the individual steps, there's a handful of assumptions. First, you have a server you can SSH into and it's serving your site via Nginx. You should also have a domain name already setup, no bare IP addresses.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order to validate that you own the domain that you're attempting to configure the certificate for, you'll need to expose the &lt;code&gt;.well-known&lt;/code&gt; path. Modify your &lt;code&gt;sites-available/default&lt;/code&gt; Nginx configuration to add the following location.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;location ~ /.well-known { 
    allow all; 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This directive ensures that requests to &lt;code&gt;/.well-known&lt;/code&gt; will succeed. The is necessary to support the &lt;a href="https://letsencrypt.org/docs/challenge-types/"&gt;ACME Challenge&lt;/a&gt; from Let's Encrypt. This challenge is used to verify that you own the domain name.&lt;/p&gt;
&lt;p&gt;Now that Nginx is configured to allow certification of your domain, it's time to run the &lt;code&gt;certbot&lt;/code&gt; command to validate the domain.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;certbot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;certonly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;webroot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;webroot&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command will validate that you own the domain for which you are requesting a certificate, place that certificate in &lt;code&gt;/etc/letsencrypt&lt;/code&gt;. After the certificate is generated, you'll need to configure Nginx to use TLS/SSL. The recommended way to do this is to generate Nginx "snippets" containing the required configuration. &lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo vi /etc/nginx/snippets/ssl-example.com.conf&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Inside the snippet file, add the following lines, replacing your domain name as required.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we need to create a snippet for setting strong encryption settings. Run &lt;code&gt;sudo vi /etc/nginx/snippets/ssl-params.conf&lt;/code&gt; to create the file. Below I'll include how I have my file setup, but you should probably reference &lt;a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html"&gt;raymii.org&lt;/a&gt; for up-to-date instructions on configuring SSL, as these recommendations will change over time.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ssl_protocols&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TLSv1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TLSv1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;ssl_prefer_server_ciphers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;ssl_ciphers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ECDHE&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;RSA&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;AES256&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;GCM&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SHA512&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;DHE&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;RSA&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;AES256&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;GCM&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SHA512&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ECDHE&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;RSA&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;AES256&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;GCM&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SHA384&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;DHE&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;RSA&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;AES256&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;GCM&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SHA384&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ECDHE&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;RSA&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;AES256&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SHA384&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;ssl_dhparam&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;certs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dhparam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;ssl_ecdh_curve&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;secp384r1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;ssl_session_cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SSL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;ssl_session_tickets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;

&lt;span class="n"&gt;ssl_stapling&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;ssl_stapling_verify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;resolver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;8.8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;resolver_timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;

&lt;span class="c1"&gt;# disable HSTS header for now &lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;add_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Strict&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Security&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;max-age=63072000; includeSubDomains; preload&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;add_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Frame&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DENY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;add_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nosniff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's about it. Overall I was pleased with how easy the setup was. Having an unencrypted server is no longer an option for me.&lt;/p&gt;</content><category term="development"></category><category term="web"></category><category term="ssl"></category><category term="server"></category></entry><entry><title>Creating a Swift Collection</title><link href="https://jimkubicek.com/creating-a-swift-collection.html" rel="alternate"></link><published>2015-02-16T14:14:00-08:00</published><updated>2015-02-16T14:14:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2015-02-16:/creating-a-swift-collection.html</id><summary type="html">&lt;p&gt;Let's say you'd like to create your own collection class. In this example, it's going to be a collection of books that only allow the addition of a new book if it's written by a select list of your favorite authors.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;MyCollection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Let's say you'd like to create your own collection class. In this example, it's going to be a collection of books that only allow the addition of a new book if it's written by a select list of your favorite authors.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;MyCollection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;validAuthors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Tom Robbins&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Jim Davis&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validAuthors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So good so far. Now we need to add some accessors. It would be nice to know how many books are in the collection. Indexed access to the books would be great. The ability to iterate over our books in a &lt;code&gt;for x in y&lt;/code&gt; block would be fantastic. Let's go about adding that behavior.&lt;/p&gt;
&lt;p&gt;In order to enable using our collection in a for loop, we've got to adopt the &lt;code&gt;CollectionType&lt;/code&gt; protocol. Let's add that to our &lt;code&gt;MyCollection&lt;/code&gt; declaration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;CollectionType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's read the definition of the &lt;code&gt;CollectionType&lt;/code&gt; protocol.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;CollectionType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;_CollectionType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;SequenceType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;subscript&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Well then. That looks simple, except what is &lt;code&gt;Self.Index&lt;/code&gt; and &lt;code&gt;Self.Generator.Element&lt;/code&gt;? Let's read the definition of &lt;code&gt;_CollectionType&lt;/code&gt; and &lt;code&gt;SequenceType&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;_CollectionType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;_SequenceType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;/// A type that represents a valid position in the collection.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// Valid indices consist of the position of every element and a&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;quot;past the end&amp;quot; position that&amp;#39;s not valid for use as a subscript.&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;ForwardIndexType&lt;/span&gt;

    &lt;span class="c1"&gt;/// The position of the first element in a non-empty collection.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// Identical to `endIndex` in an empty collection.&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;startIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// The collection&amp;#39;s &amp;quot;past the end&amp;quot; position.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// `endIndex` is not a valid argument to `subscript`, and is always&lt;/span&gt;
    &lt;span class="c1"&gt;/// reachable from `startIndex` by zero or more applications of&lt;/span&gt;
    &lt;span class="c1"&gt;/// `successor()`.&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;endIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;_Element&lt;/span&gt;
    &lt;span class="kd"&gt;subscript&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;SequenceType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;_Sequence_Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;/// A type that provides the *sequence*\ &amp;#39;s iteration interface and&lt;/span&gt;
    &lt;span class="c1"&gt;/// encapsulates its iteration state.&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;GeneratorType&lt;/span&gt;

    &lt;span class="c1"&gt;/// Return a *generator* over the elements of this *sequence*.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// Complexity: O(1)&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Informative. Now we need to know what &lt;code&gt;_SequenceType&lt;/code&gt;, &lt;code&gt;ForwardIndexType&lt;/code&gt; &lt;code&gt;_Sequence_Type&lt;/code&gt;, and &lt;code&gt;GeneratorType&lt;/code&gt; do.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;_SequenceType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;ForwardIndexType&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;_ForwardIndexType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;_Sequence_Type&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;_SequenceType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;/// A type whose instances can produce the elements of this&lt;/span&gt;
    &lt;span class="c1"&gt;/// sequence, in order.&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;GeneratorType&lt;/span&gt;

    &lt;span class="c1"&gt;/// Return a *generator* over the elements of this *sequence*.  The&lt;/span&gt;
    &lt;span class="c1"&gt;/// *generator*\ &amp;#39;s next element is the first element of the&lt;/span&gt;
    &lt;span class="c1"&gt;/// sequence.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// Complexity: O(1)&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;GeneratorType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;/// The type of element generated by `self`.&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Element&lt;/span&gt;

    &lt;span class="c1"&gt;/// Advance to the next element and return it, or `nil` if no next&lt;/span&gt;
    &lt;span class="c1"&gt;/// element exists.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// Requires: `next()` has not been applied to a copy of `self`&lt;/span&gt;
    &lt;span class="c1"&gt;/// since the copy was made, and no preceding call to `self.next()`&lt;/span&gt;
    &lt;span class="c1"&gt;/// has returned `nil`.  Specific implementations of this protocol&lt;/span&gt;
    &lt;span class="c1"&gt;/// are encouraged to respond to violations of this requirement by&lt;/span&gt;
    &lt;span class="c1"&gt;/// calling `preconditionFailure(&amp;quot;...&amp;quot;)`.&lt;/span&gt;
    &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Whew. I think we've exhausted that rabbit hole. Now we can start building up our collection class. First, let's create a book generator. Since the specifics of this type only need to be known to &lt;code&gt;MyCollection&lt;/code&gt;, we're free to create it as a private inner struct.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BookGenerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;GeneratorType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="kd"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endIndex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Fantastic. Now let's take a look at how we're going to adopt the &lt;code&gt;_SequenceType&lt;/code&gt; protocol.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;GeneratorOf&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;GeneratorOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BookGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a bit of trickery. The &lt;code&gt;GeneratorOf&amp;lt;Book&amp;gt;&lt;/code&gt; type is a type-erasing generator. &lt;code&gt;GeneratorOf&lt;/code&gt; is a &lt;code&gt;GeneratorType&lt;/code&gt; that takes a &lt;code&gt;Generator&lt;/code&gt; on initialization. Using &lt;code&gt;GeneratorOf&lt;/code&gt; as our generator type allows us to declare a public &lt;code&gt;generate()&lt;/code&gt; method that returns a known type (&lt;code&gt;GeneratorOf&lt;/code&gt;) without exposing to the world the &lt;em&gt;actual&lt;/em&gt; &lt;code&gt;Generator&lt;/code&gt; type we're using.&lt;/p&gt;
&lt;p&gt;Now, how are we going to adopt &lt;code&gt;_CollectionType&lt;/code&gt;?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;
&lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;_Element&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;startIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startIndex&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;endIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endIndex&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="kd"&gt;subscript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We're looking great! Let's test it out.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;mine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyCollection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Wild Ducks Flying Backwards&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Tom Robbins&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;mine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A Garfield Treasury, Vol 14&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Jim Davis&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mine&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="bp"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Works great! For completeness, here's all the code from my test playground:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Cocoa&lt;/span&gt;

&lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;MyCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;CollectionType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;GeneratorOf&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;
    &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;_Element&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;validAuthors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Tom Robbins&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Jim Davis&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;startIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startIndex&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;endIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endIndex&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;BookGenerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;GeneratorType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="n"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="kd"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endIndex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validAuthors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;GeneratorOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BookGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;subscript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_Element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;mine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyCollection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Wild Ducks Flying Backwards&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Tom Robbins&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;mine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addBook&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A Garfield Treasury, Vol 14&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Jim Davis&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mine&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="bp"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="development"></category><category term="swift"></category></entry><entry><title>Creating a Homebrew formula for a Python project</title><link href="https://jimkubicek.com/creating-a-homebrew-formula-for-a-python-project.html" rel="alternate"></link><published>2015-02-14T21:13:00-08:00</published><updated>2015-02-14T21:13:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2015-02-14:/creating-a-homebrew-formula-for-a-python-project.html</id><summary type="html">&lt;p&gt;I just finished writing a homebrew formula for a python script I wrote, I'm going to walk through how I did it. Hopefully this helps anyone else who is thinking about distributing their code.&lt;/p&gt;
&lt;p&gt;Why did I use &lt;a href="homebrew"&gt;Homebrew&lt;/a&gt; and not Pip? Two reasons: first, my code requires some Java …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I just finished writing a homebrew formula for a python script I wrote, I'm going to walk through how I did it. Hopefully this helps anyone else who is thinking about distributing their code.&lt;/p&gt;
&lt;p&gt;Why did I use &lt;a href="homebrew"&gt;Homebrew&lt;/a&gt; and not Pip? Two reasons: first, my code requires some Java .jar files. The front end is python, but a big chuck of the code is Java, so I didn't have any particular allegiance to Pip. Second, I think Homebrew is the most common package distribution method on OS X. Not everyone will have Pip installed, but anyone who can use my script, will have Homebrew installed (It is the easiest way to install &lt;a href="keybase"&gt;Keybase&lt;/a&gt;, which I require).&lt;/p&gt;
&lt;p&gt;As an example, I'm going to write a Formula to install my python script &lt;a href="switters"&gt;Switters&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, you should push your package to Github. This will give you both a place to host your downloads and a homepage URL that you will need to add to your Formula. Homebrew requires that you version your project, so make sure your commit is tagged with a version. &lt;/p&gt;
&lt;p&gt;You'll need to find the download link for your repo. Checkout the &lt;em&gt;Releases&lt;/em&gt; page on github for the download URL. It should look something like &lt;code&gt;https://github.com/jkubicek/Switters/archive/0.1.2.tar.gz&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;Now, run the command to create your formula.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;jkubicek&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="no"&gt;Switters&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;archive&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This creates a formula at &lt;code&gt;$HOMEBREW_REPOSITORY/Library/Formula/switters.rb&lt;/code&gt; and opens it in your text editor. If you get a warning, "Version cannot be determined from URL", add the correct version to the formula with &lt;code&gt;version '0.1.1'&lt;/code&gt;. You'll also need to add your homepage. It's fine to use the project's Github page here.&lt;/p&gt;
&lt;p&gt;Homebrew recommends that you explicitly add your python dependencies. For dependencies hosted on &lt;a href="pypi"&gt;PyPI&lt;/a&gt; that means you'll need to browse &lt;a href="pypi"&gt;PyPI&lt;/a&gt; to find the download URL for your resource. Here's an example resource entry for &lt;code&gt;Tweetpony&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tweetpony&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://pypi.python.org/packages/source/T/TweetPony/tweetpony-1.5.0.tar.gz&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;sha1&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;c6e217f2676e9980a5ad01d0da125f0e1914398a&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The URL is straight from the &lt;a href="pypi"&gt;PyPI&lt;/a&gt; page. PyPI only gives you the MD5 hash, which is no longer recommended for Homebrew. To get the sha1 hash, use &lt;code&gt;shasum&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt; &lt;span class="ss"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;pypi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="no"&gt;TweetPony&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tweetpony&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gz&lt;/span&gt;
&lt;span class="n"&gt;shasum&lt;/span&gt; &lt;span class="n"&gt;tweetpony&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Copy the resultant SHA into your forumla.&lt;/p&gt;
&lt;p&gt;Now you'll need to check the build system. Don't bother with Homebrew's interactive installation. It doesn't run your install method, so it doesn't let you debug the installation steps. Instead, run a regular install command with a few helpful flags. The results of the &lt;code&gt;--verbose&lt;/code&gt; flag are obvious. The &lt;code&gt;--debug&lt;/code&gt; flag will stop the installation on errors and give you an interactive prompt. From here you may print a stack trace or open up an IRB session. Very helpful.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt; &lt;span class="n"&gt;switters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Take note of the SHA that Homebrew reports, you should add this to your Formula. &lt;/p&gt;
&lt;p&gt;If everything goes well, the script should have run successfully and... nothing should have been installed. You've got to add the installation method.&lt;/p&gt;
&lt;p&gt;First, let me explain the structure of my &lt;a href="switters"&gt;Switters project&lt;/a&gt;. I've got an executable at the top level of my project. There are two local python modules, &lt;code&gt;switterslib&lt;/code&gt; and &lt;code&gt;zxing&lt;/code&gt; and two Java .jars located in &lt;code&gt;zxing_java&lt;/code&gt;. In order for everything to work, I've got to make sure my imports from &lt;a href="pypi"&gt;PyPI&lt;/a&gt; are installed correctly and that the local resources are put in the correct spot. First, lets get our remote resources setup.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prepend_create_path&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;PYTHONPATH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vendor/lib/python2.7/site-packages&amp;quot;&lt;/span&gt;
&lt;span class="sx"&gt;%w[tweetpony qrcode requests]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;python&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;Language&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Python&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_install_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vendor&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What does this do? First, we append &lt;code&gt;HOMEBREW_PREFIX+"Cellar"+name+version+"libexec/vendor/lib/python2.7/site-packages&lt;/code&gt; onto the &lt;code&gt;PYTHONPATH&lt;/code&gt; environment variable. This ensures that Python will be aware of this directory and look here for the necessary modules. We'll see how that works in a bit. Next, we iterate through our resources, create a &lt;code&gt;stage&lt;/code&gt; environment, and call a special Homebrew python command that installs our dependancies into &lt;code&gt;libexec/vendor&lt;/code&gt;. After installation, the actual location of these libraries will be &lt;code&gt;libexec/vendor/lib/python2.7/site-packages&lt;/code&gt;, hence the environment variable we set as our first step.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prepend_create_path&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;PYTHONPATH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;libexec&lt;/span&gt;
&lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;switterslib&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;zxing&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;zxing_java&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, we append the raw &lt;code&gt;libexec&lt;/code&gt; path onto &lt;code&gt;PYTHONPATH&lt;/code&gt; and copy the &lt;code&gt;switterslib&lt;/code&gt;, &lt;code&gt;zxing&lt;/code&gt; and &lt;code&gt;zxing_java&lt;/code&gt; directories into it. This ensures that when our formula is installed, our python script can find these packages.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;switters&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env_script_all_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:PYTHONPATH&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PYTHONPATH&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, we install our script into the bin directory and run the &lt;code&gt;env_script_all_files&lt;/code&gt; command on everything in the &lt;code&gt;bin&lt;/code&gt; directory. This creates a shell script that sets up our python environment (hence having to add specific directories into &lt;code&gt;PYTHONPATH&lt;/code&gt;) and calls each script in the &lt;code&gt;bin&lt;/code&gt; directory. This script is located in the &lt;code&gt;HOMEBREW_PREFIX+"Cellar"+name+version+"/bin"&lt;/code&gt; dir. Everything in this directory is then symlinked into &lt;code&gt;/usr/local/bin/&lt;/code&gt; which is (hopefully) in your &lt;code&gt;PATH&lt;/code&gt; and now you'll be able to call the script from anywhere!&lt;/p&gt;</content><category term="development"></category></entry><entry><title>I'm learning Android Dev</title><link href="https://jimkubicek.com/im-learning-android-dev.html" rel="alternate"></link><published>2013-11-02T21:51:00-07:00</published><updated>2013-11-02T21:51:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2013-11-02:/im-learning-android-dev.html</id><summary type="html">&lt;p&gt;It's about time I took a look and saw how the other half lived. I'm learning Android development. I bought the &lt;a href="http://www.bignerdranch.com/book/android_the_big_nerd_ranch_guide"&gt;BNR Android book&lt;/a&gt; and have started working my way through the chapters. Keeping in mind I've only been doing this for two or three days, here are my thoughts …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It's about time I took a look and saw how the other half lived. I'm learning Android development. I bought the &lt;a href="http://www.bignerdranch.com/book/android_the_big_nerd_ranch_guide"&gt;BNR Android book&lt;/a&gt; and have started working my way through the chapters. Keeping in mind I've only been doing this for two or three days, here are my thoughts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Big Nerd Ranch writes exceptional books.&lt;/li&gt;
&lt;li&gt;The Android Emulator is slow. It's like DMV slow.&lt;/li&gt;
&lt;li&gt;I've spent a surprising amount of time cleaning builds and restarting Eclipse and the emulator. I wouldn't expect to get into that kind of debugging so quickly, especially on such a simple project. And while I'm complaining about Eclipse, non of their image assets are Retina. Since this is the only non-retina app I've used in a while, the appearance is strikingly bad.&lt;/li&gt;
&lt;li&gt;String handling in Android is much better than in iOS. Has anyone written anything similar for iOS? Checking the googles...&lt;/li&gt;
&lt;li&gt;I haven't used Java since 2006 or 2007. It was surprisingly easy to pick back up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I realize that my complaints about Eclipse and the emulator can be fixed by switching to a different IDE and using &lt;a href="http://www.genymotion.com"&gt;alternate emulators&lt;/a&gt;, but I'm making a conscious effort to learn the official way to develop Android apps before I strike out on my own and customize my own environment.&lt;/p&gt;</content><category term="misc"></category></entry><entry><title>Waterfield Designs Staad Backback</title><link href="https://jimkubicek.com/waterfield-designs-staad-backback.html" rel="alternate"></link><published>2013-10-17T08:00:00-07:00</published><updated>2013-10-17T08:00:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2013-10-17:/waterfield-designs-staad-backback.html</id><summary type="html">&lt;p&gt;Just a few weeks ago &lt;a href="http://www.sfbags.com"&gt;Waterfield Designs&lt;/a&gt; released their first pack, the &lt;a href="http://www.sfbags.com/products/backpacks/staad-backpack.php"&gt;Staad Backback&lt;/a&gt;. Strangely enough, every review I've seen is just a regurgitation of the press release and the product page, so I thought I'd give a little write-up after actually handling the pack. &lt;/p&gt;
&lt;p&gt;First, my current backpack is …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Just a few weeks ago &lt;a href="http://www.sfbags.com"&gt;Waterfield Designs&lt;/a&gt; released their first pack, the &lt;a href="http://www.sfbags.com/products/backpacks/staad-backpack.php"&gt;Staad Backback&lt;/a&gt;. Strangely enough, every review I've seen is just a regurgitation of the press release and the product page, so I thought I'd give a little write-up after actually handling the pack. &lt;/p&gt;
&lt;p&gt;First, my current backpack is the &lt;a href="http://www.tombihn.com/backpacks/TB0103.html"&gt;Tom Bihn Smart Alec&lt;/a&gt;. This is the best backpack I have ever owned. It's comfortable, it's durable, it's sufficiently waterproof to ride my bike to work in a downpour. It has the most usable pocket system I've ever seen in a backpack. It's also a bit big for what I need day-to-day, so I've been casually browsing around for a something smaller to get me back and forth to work.&lt;/p&gt;
&lt;p&gt;After seeing my at the Staad, I decided to go with the waxed canvas, chocolate leather slim version of the bag. I went back and forth on the sizing, but I currently have a 13" laptop and a bag big enough to haul groceries in, so if I'm going to buy a new bag I might as well go with the smallest bag that's useful.&lt;/p&gt;
&lt;h2&gt;First Impressions&lt;/h2&gt;
&lt;p&gt;As I write this, I have just recived the pack, so I don't have any real usage notes to report. Here are my first impressions; things that I was wondering about, I've seen people ask about or details that surprise me.&lt;/p&gt;
&lt;p&gt;The buckle is not vintage. Every review I've read mentions the "vintage" buckle. I think what they mean is it is a "vintage style" buckle. The buckle itself is brand-new and plastic. That being said, it's an interesting buckle. If you watch &lt;a href="http://www.sfbags.com/products/backpacks/staad-backpack.php"&gt;Gary's video&lt;/a&gt; notice how smoothly he opens the flap. It really is that smooth. The video glosses over the closing action a bit and makes it hard to see the exact mechanism for closing the bag. When you want to close the bag, you push the main tab down, then manipulate the small plastic bit through the slot. On a brand new Staad this is easy, as the stiffness of the webbing and the leather tab keeps everything in place and ready to close. I'm interested to see how this changes as the bag ages and everything breaks in.&lt;/p&gt;
&lt;p&gt;Here are some animations illustrating the opening and closing action:&lt;/p&gt;
&lt;p&gt;&lt;img alt="opening the clasp" src="/images/bag1.gif"&gt;
&lt;img alt="closing the clasp" src="/images/bag2.gif"&gt;&lt;/p&gt;
&lt;p&gt;This clasp is fun to operate. It is one of the most satisfying closures I've used,  rivaling the feeling you get when you rip open the fly on old broken-in button fly jeans.&lt;/p&gt;
&lt;p&gt;The outside pockets are small, best suited to thin objects. I've got medium sized hands, the pockets are almost the exact size of my hands. Too small for a Moleskine, just right for Field Notes. You aren't going be fitting a water bottle in here. These pockets are best suited for small items, earbuds, wallets, notebooks, gum, etc. Because of the stiffness of the waxed canvas, the pockets don't stretch or deform, so you aren't going to be able to cram a lot of stuff in there even if you wanted to.&lt;/p&gt;
&lt;p&gt;I didn't notice this in any images or descriptions, but the laptop and iPad pockets have a very nice fleece lining. The iPod pocket is thin, just big enough for a bare iPad (I couldn't put my iPad mini + cover in the pocket without the cover sliding off).&lt;/p&gt;
&lt;p&gt;I had two bottles of wine in the house. Both fit into the main compartment easily and I think I could have fit a third in there. This assumes that none of the other pockets have anything bulky in them. The pocket tapers towards the top, so putting the wine in requires unzipping the zipper. Once zipped it is fairly secure and the wine doesn't fall out even when the bag is inverted. There's no way you could fit a six-pack without taking the bottles out of the carrier.&lt;/p&gt;
&lt;p&gt;The main compartment won't fit anything much bigger than a long-sleeved t-shirt. Pack light.&lt;/p&gt;
&lt;p&gt;The underside of the flap is black leather. &lt;/p&gt;
&lt;p&gt;Zipper pulls are generic plastic pulls. They're fine, same pulls my Tom Bihn bag uses. I wish bag makers like Waterfield Designs and Tom Bihn would use something a little nicer, though. &lt;/p&gt;
&lt;p&gt;Laptop sleeve ends about 2 inches above the bottom of the bag. You'd have to set the bag down very hard to have the laptop bump.&lt;/p&gt;
&lt;p&gt;The interior pockets close with Velcro, but it's a nice Velcro. The loop part is tight, the hook part is not rough or scratchy; it's almost smooth. The pockets are not deep. A Field Notes notebook sticks up enough that the velcro closure cannot close.&lt;/p&gt;
&lt;p&gt;This is probably obvious to everyone considering this bag, but it's worth being explicit: this bag is going to get a worn look very quickly. The leather flap already has scratches on it from me opening and closing the clasp. The waxed canvas has some scuffs. Anyone considering buying this bag probably desires the broken-in look, but if you like your gear to keep looking pristine, this is likely not the bag for you.&lt;/p&gt;</content><category term="reviews"></category></entry><entry><title>Amend Files to Previous Commit</title><link href="https://jimkubicek.com/amend-files-to-previous-commit.html" rel="alternate"></link><published>2013-08-08T09:40:00-07:00</published><updated>2013-08-08T09:40:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2013-08-08:/amend-files-to-previous-commit.html</id><summary type="html">&lt;p&gt;I run into this frequently when doing big a big refactor. I'm carefully committing my changes in nice bisectable units, but then Woah! there's a change that should be included in a previous commit. Here's how you fix this up in Git. &lt;/p&gt;
&lt;p&gt;Disclaimer: We are modifying Git history. Do not …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I run into this frequently when doing big a big refactor. I'm carefully committing my changes in nice bisectable units, but then Woah! there's a change that should be included in a previous commit. Here's how you fix this up in Git. &lt;/p&gt;
&lt;p&gt;Disclaimer: We are modifying Git history. Do not do this if you have already pushed these changes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ git log --oneline

39e1678 Removed allowsAirPlayVideo method
6c750a1 Removed UILineBreak enums
ce2c34f Removed all UITextAlignment enums
a5c04ad Remove dispatch_release&lt;span class="o"&gt;()&lt;/span&gt; calls
&lt;span class="m"&gt;8681487&lt;/span&gt; Removed Refresh Header
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There we go. My current changes should be included in commit &lt;code&gt;8681487&lt;/code&gt;, "Removed Refresh Header". Fixing this is easy. Add your changes to the staging area, then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git commit --fixup=8681487
git rebase --interactive --autosquash 8681487~1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first command commits your changes, but modifies the commit message to be the same as &lt;code&gt;8681487&lt;/code&gt; with "fixup!" appended in front. Running rebase in interactive mode with "autosquash" turned on will move our previous commit right after the commit we'd like to modify and update that commit with our new changes.&lt;/p&gt;
&lt;p&gt;Easy as pie!&lt;/p&gt;</content><category term="development"></category></entry><entry><title>Debugging Smashed Memory in Obj-C</title><link href="https://jimkubicek.com/debugging-smashed-memory-in-obj-c.html" rel="alternate"></link><published>2013-04-23T22:32:00-07:00</published><updated>2013-04-23T22:32:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2013-04-23:/debugging-smashed-memory-in-obj-c.html</id><summary type="html">&lt;p&gt;We were getting a crash inside a button. Calling &lt;code&gt;po self&lt;/code&gt; wasn't helpful.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(lldb) po self
$1 = 0x0ce854d0 [no Objective-C description available]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Well.. That's weird. I wonder what's at that memory location?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(lldb) memory read 0x0ce854d0
0x0ce854d0: 00 00 00 b0 93 6a ce a0 0e 00 00 00 00 …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;We were getting a crash inside a button. Calling &lt;code&gt;po self&lt;/code&gt; wasn't helpful.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(lldb) po self
$1 = 0x0ce854d0 [no Objective-C description available]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Well.. That's weird. I wonder what's at that memory location?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(lldb) memory read 0x0ce854d0
0x0ce854d0: 00 00 00 b0 93 6a ce a0 0e 00 00 00 00 00 00 00  .....j..........
0x0ce854e0: 10 c7 e7 0c 00 00 00 00 00 00 00 00 00 00 00 00  ................
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That... doesn't look right. Let's turn on some debugging tools and see if that helps. Open the 'Edit Scheme' window and navigate to the Diagnostics tab. You'll want to turn on "Enable Scribble" and "Malloc Stack". You can read more about these methods &lt;a href="https://developer.apple.com/library/mac/#releasenotes/DeveloperTools/RN-MallocOptions/"&gt;here&lt;/a&gt;, but in short, "Enabled Scribble" will cause the allocator to write &lt;code&gt;0xAA&lt;/code&gt; to newly allocated memory and write &lt;code&gt;0x55&lt;/code&gt; to deallocated memory. "Malloc Stack" will log the allocation and free history of your memory.&lt;/p&gt;
&lt;p&gt;&lt;img alt="debugging settings" src="/images/debugging-memory-smashers.png"&gt;&lt;/p&gt;
&lt;p&gt;Let's get our app to crash again and see if that helped.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(lldb) po self
$1 = 0x0cdcd2d0 [no Objective-C description available]
(lldb) memory read 0x0cdcd2d0
0x0cdcd2d0: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55  UUUUUUUUUUUUUUUU
0x0cdcd2e0: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55  UUUUUUUUUUUUUUUU
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Well, there we go. Obviously someone else is freeing self while we're in the middle of a method. Let's grab the PID of our crashing process. Easiest way to get this from an iOS app is to check out any log statements in the terminal.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;2013&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;04&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;59&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;38.194&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Sin&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="err"&gt;![&lt;/span&gt;&lt;span class="mf"&gt;14105&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2203&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Log&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="n"&gt;PID&lt;/span&gt;&lt;span class="o"&gt;^^^^^&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Mosey on over to your trusty terminal and let's see what's happening at that memory address.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ malloc_history &lt;span class="m"&gt;14105&lt;/span&gt; 0x0cdcd2d0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is going to fill your screen with a massive spew of text. You'll probably want to pipe the results to your text editor of choice. The important bits are right there at the top, though. Check it out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ALLOC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;FREE&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mh"&gt;0xcdcd2d0-0xcdcd3a7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CFRunLoopTimerInvalidate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_timerRelease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SongPreviewButton&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dealloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;About 100 lines of junk omitted. But there you go. We've got a timer that's holding on to a button, preventing it from being freed when it should be, then all of a sudden the timer lets go and everything falls apart. Simple!&lt;/p&gt;</content><category term="development"></category><category term="debugging"></category></entry><entry><title>List Rake Tasks by Default</title><link href="https://jimkubicek.com/list-rake-tasks-by-default.html" rel="alternate"></link><published>2013-01-27T13:57:00-08:00</published><updated>2013-01-27T13:57:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2013-01-27:/list-rake-tasks-by-default.html</id><summary type="html">&lt;p&gt;I add this to all my Rakefiles.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:default&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rake --tasks&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It prints a list of Rake tasks when you run Rake without a command. Not only does it help you remember what options are available in the current project, but it keeps you from accidentally performing …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I add this to all my Rakefiles.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:default&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rake --tasks&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It prints a list of Rake tasks when you run Rake without a command. Not only does it help you remember what options are available in the current project, but it keeps you from accidentally performing some task if you fat-finger the &lt;code&gt;rake&lt;/code&gt; command.&lt;/p&gt;</content><category term="development"></category></entry><entry><title>Unit Testing Parse Cloud Code</title><link href="https://jimkubicek.com/unit-testing-parse-cloud-code.html" rel="alternate"></link><published>2013-01-26T23:53:00-08:00</published><updated>2013-01-26T23:53:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2013-01-26:/unit-testing-parse-cloud-code.html</id><summary type="html">&lt;p&gt;Like many people, I was thrilled when Parse announced their &lt;a href="https://www.parse.com/products/cloud_code" title="Cloud Code"&gt;cloud code&lt;/a&gt; product. I've just started a little iOS project that required both persistent cloud storage and pulling data from a 3rd party API. Since the API had a great JavaScript library, but no built-in Obj-C support, moving the code …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Like many people, I was thrilled when Parse announced their &lt;a href="https://www.parse.com/products/cloud_code" title="Cloud Code"&gt;cloud code&lt;/a&gt; product. I've just started a little iOS project that required both persistent cloud storage and pulling data from a 3rd party API. Since the API had a great JavaScript library, but no built-in Obj-C support, moving the code onto the server had some big benefits: greatly simplified networking in iOS, allowed me to reuse the 3rd party library as is, and decreases my turnaround time should I need to modify this code in the future. &lt;/p&gt;
&lt;p&gt;Now, I'm usually not a strict test driven developer, but these cloud code modules are a different story; the code is running on a server and accessing a 3rd party API. In this situation, quick build/test/debug cycles are impossible and testing is the only way go. &lt;/p&gt;
&lt;p&gt;Here's how I set up my testing environment. Please keep in mind that this is the first time I've used Node.js, first time I've written unit tests for JavaScript and the first real JS project I've worked on. In fact, before this, the only JS code I'd written was hackly little Safari extensions, so this is a whole new world for me. I'm writing this for someone with experience similar to mine; if you are experienced with Node, feel free to skip ahead.&lt;/p&gt;
&lt;h2&gt;Setting up the test environment&lt;/h2&gt;
&lt;p&gt;I assume you've already got &lt;a href="http://nodejs.org" title="node.js"&gt;Node&lt;/a&gt; and &lt;a href="https://npmjs.org" title="npm"&gt;npm&lt;/a&gt; installed. If you don't, they both can be installed via &lt;a href="http://mxcl.github.com/homebrew/" title="homebrew"&gt;Homebrew&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I used &lt;a href="http://visionmedia.github.com/mocha/" title="mocha.js"&gt;Mocha.js&lt;/a&gt; for the testing framework and &lt;a href="https://github.com/LearnBoost/expect.js/" title="expect.js"&gt;Expect.js&lt;/a&gt; for assertions. Mocha supports any assertion framework you can throw at it. &lt;code&gt;Expect&lt;/code&gt; seems to work well and doesn't generate &lt;code&gt;Lint&lt;/code&gt; warnings like &lt;code&gt;Should.js&lt;/code&gt;. Run the following commands from your project directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ npm install mocha
$ npm install expect.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These commands install the mocha and expect frameworks in the local &lt;code&gt;node_modules&lt;/code&gt; directory. This greatly simplifies your environment. Code can be shared between collaborators without worrying about what framework version each dev has installed.&lt;/p&gt;
&lt;p&gt;At this point, your Parse directory should look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cloud /
  main.js
config /
  global.json
node_modules /
  .bin /
  mocha /
  expect /
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Creating Cloud Code Modules&lt;/h2&gt;
&lt;p&gt;We're all set to test, but first we need something to test. We're going to add some code that just returns a helpful message. Modify &lt;code&gt;main.js&lt;/code&gt; to look like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cloud/message.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nx"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;get_message&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What I've done is load each Cloud Code function from a separate module, this worked well for me because each function is independent of all other functions, but YMMV. Let's setup some code to test. First, create a file named &lt;code&gt;message.js&lt;/code&gt; in your &lt;code&gt;cloud&lt;/code&gt; directory. Now modify it to look like so.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMessage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Good job, buddy&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A bit about how &lt;code&gt;Node.js&lt;/code&gt; loads modules, since this was all new to me. When each module is loaded, there is an object created called &lt;code&gt;exports&lt;/code&gt; that is available within that module. Any function attached to that object will be available externally when your module is loaded. So in this example, our &lt;code&gt;message&lt;/code&gt; module creates one function called &lt;code&gt;getMessage&lt;/code&gt;. When we call &lt;code&gt;var message = require('cloud/message.js');&lt;/code&gt; the object returned from the &lt;code&gt;require()&lt;/code&gt; function is that &lt;code&gt;exports&lt;/code&gt; object.&lt;/p&gt;
&lt;h2&gt;Creating Tests&lt;/h2&gt;
&lt;p&gt;Now let's create some tests. First, the default directory for &lt;code&gt;Mocha&lt;/code&gt; tests is &lt;code&gt;test&lt;/code&gt;, so let's put our test there. Create the test directory and put a file in there named, "messageTests.js". Modify it to look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;../cloud/message.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;expect.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;response&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;should return the correct message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;No tests yet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First we import our &lt;code&gt;message&lt;/code&gt; and &lt;code&gt;expect&lt;/code&gt; modules. The &lt;code&gt;describe()&lt;/code&gt; function is used to define the scope for associated tests. The &lt;code&gt;it()&lt;/code&gt; function defines a Mocha test. Let's run our test.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ node_modules/.bin/mocha
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that the error message says, "Message response should return the correct message:", so structure your &lt;code&gt;describe&lt;/code&gt; and &lt;code&gt;it&lt;/code&gt; messages to make that message nice and readable. Let's replace our failing test with an actual tests.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;should return the correct message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Good job, buddy&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There's a few things to notice here. First, the &lt;code&gt;done()&lt;/code&gt; function is an optional parameter to the &lt;code&gt;describe()&lt;/code&gt; and &lt;code&gt;it()&lt;/code&gt; methods. Any tests within will not complete successfully until the &lt;code&gt;done()&lt;/code&gt; function is called, so you can use it to test callbacks and ensure that they were called. Second, notice the format of the &lt;code&gt;expect()&lt;/code&gt; function. You can read the &lt;a href="https://github.com/LearnBoost/expect.js/" title="expect.js"&gt;documentation&lt;/a&gt; for more details, but in general, the tests always follow this form, beginning with an &lt;code&gt;expect()&lt;/code&gt; function and ending with a function. &lt;/p&gt;
&lt;p&gt;Run the tests again and success! All our tests pass. All in all, it took me less than a day to try out different testing and exception modules, settle on &lt;code&gt;Mocha&lt;/code&gt; and &lt;code&gt;Expect&lt;/code&gt;, then write enough tests to nearly fully cover the Cloud Code I had written. Coming from Objective-C, the power and flexibility of JavaScript amazes me. Writing these tests was almost a joy.   &lt;/p&gt;</content><category term="misc"></category></entry><entry><title>JSLint: Expected 'return' at column X, not column Y</title><link href="https://jimkubicek.com/jslint-expected-return-at-column-x-not-column-y.html" rel="alternate"></link><published>2013-01-17T07:51:00-08:00</published><updated>2013-01-17T07:51:00-08:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2013-01-17:/jslint-expected-return-at-column-x-not-column-y.html</id><summary type="html">&lt;p&gt;I've been writing some Javascript using the default settings in &lt;a href="http://chocolatapp.com"&gt;Chocolat&lt;/a&gt;, tabs instead of spaces and each tab is equivalent to 2 spaces. Running most of my javascript files through JSLint is fine, but there were a few lines that were generating warnings, even though the spacing looked just fine …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been writing some Javascript using the default settings in &lt;a href="http://chocolatapp.com"&gt;Chocolat&lt;/a&gt;, tabs instead of spaces and each tab is equivalent to 2 spaces. Running most of my javascript files through JSLint is fine, but there were a few lines that were generating warnings, even though the spacing looked just fine.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;validateCardRequestDidSucceed&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;stripeResponse&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;response&lt;/span&gt;.&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Stripe card request failed with unknown error&amp;quot;&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="c1"&gt;; // Expected &amp;#39;return&amp;#39; at column 17, not column 19.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
}&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What's wrong here? That spacing looks just fine to me. Turns out that the default settings in JSLint want spaces instead of tabs and 4 spaces per indentation. JSLint, by default, ignores tabbed indentation, but somehow that return had been indented with spaces. &lt;/p&gt;
&lt;p&gt;Replacing the spaces with tabs cleared up the issue.&lt;/p&gt;
&lt;p&gt;In other news, I should probably switch to 4-space indentation. I'm not picky about spacing and, all things being equal, I might as well stick with the JSLint conventions.&lt;/p&gt;</content><category term="development"></category></entry><entry><title>When isKindOfClass is not kind of class?</title><link href="https://jimkubicek.com/when-iskindofclass-is-not-kind-of-class.html" rel="alternate"></link><published>2012-10-16T23:36:00-07:00</published><updated>2012-10-16T23:36:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-10-16:/when-iskindofclass-is-not-kind-of-class.html</id><summary type="html">&lt;p&gt;I've been running into an issue over the past few days where &lt;code&gt;[objA isKindOfClass:[ClassA class]]&lt;/code&gt; is returning false when &lt;em&gt;clearly&lt;/em&gt; objA is a kind of ClassA.
I'm running these tests using SenTesting kit and I'm &lt;em&gt;not&lt;/em&gt; compiling the &lt;code&gt;.m&lt;/code&gt; files in my test target, which is the only issue …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been running into an issue over the past few days where &lt;code&gt;[objA isKindOfClass:[ClassA class]]&lt;/code&gt; is returning false when &lt;em&gt;clearly&lt;/em&gt; objA is a kind of ClassA.
I'm running these tests using SenTesting kit and I'm &lt;em&gt;not&lt;/em&gt; compiling the &lt;code&gt;.m&lt;/code&gt; files in my test target, which is the only issue that &lt;a href="http://stackoverflow.com/questions/11675256/ismemberofclass-returns-no-when-viewcontroller-is-instantiated-from-uistoryboard"&gt;StackOverflow&lt;/a&gt; suggests.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;am&lt;/em&gt; including my Storyboards in my testing target. Perhaps that's the problem? Let me just remove those Storyboards from the testing target...&lt;/p&gt;
&lt;p&gt;BOOM. That was it.&lt;/p&gt;
&lt;p&gt;Also, for future reference, in case anyone finds their way here while looking for how to load storyboards in a SenTestingKit test target, here's how:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="bp"&gt;NSBundle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mainBundle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;NSBundle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bundleForClass&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="bp"&gt;UIStoryboard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;storyBoard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;UIStoryboard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;storyboardWithName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;mainBundle&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;viewController&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;storyBoard&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instantiateViewControllerWithIdentifier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;MainViewController&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="development"></category></entry><entry><title>Abusing UIView</title><link href="https://jimkubicek.com/abusing-uiview.html" rel="alternate"></link><published>2012-10-11T16:00:00-07:00</published><updated>2012-10-11T16:00:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-10-11:/abusing-uiview.html</id><summary type="html">&lt;p&gt;Sometimes I long for the day when I get to create an iOS app that just uses Apple's default interface element. Of course, this doesn't last long, because using and abusing &lt;code&gt;UIView&lt;/code&gt; is &lt;em&gt;fun&lt;/em&gt;. Over the years I've picked up a few tips and tricks for making the most out …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Sometimes I long for the day when I get to create an iOS app that just uses Apple's default interface element. Of course, this doesn't last long, because using and abusing &lt;code&gt;UIView&lt;/code&gt; is &lt;em&gt;fun&lt;/em&gt;. Over the years I've picked up a few tips and tricks for making the most out of your time. The best tip is, first and foremost, &lt;strong&gt;you need to start copying Apple&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This cannot be emphasized enough. Apple's framework developers aren't perfect and they &lt;em&gt;have&lt;/em&gt; made &lt;a href="http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html" title="Core Data and iCloud"&gt;mistakes&lt;/a&gt;, but overall they provide excellent frameworks, &lt;em&gt;especially&lt;/em&gt; for UI development. Make your class interfaces look like Apple's class interfaces. Try to subclass Apple's own elements before going off and creating your own. &lt;strong&gt;Don't reinvent the wheel&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That being said, any iOS app of a decent size will create many custom &lt;code&gt;UIView&lt;/code&gt; subclasses and learning how to properly subclassing &lt;code&gt;UIView&lt;/code&gt; will reap benefits.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You'll get a lot of useful behavior right out of the box.&lt;/li&gt;
&lt;li&gt;You increase readability of your code and make it easier for future developers to understand what you've written.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here are some tips for abusing &lt;code&gt;UIView&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Subclass the right class&lt;/h2&gt;
&lt;p&gt;If you are creating a generic control, subclass &lt;code&gt;UIControl&lt;/code&gt;. If you are creating a custom button, subclass &lt;code&gt;UIButton&lt;/code&gt; (or just create a custom button! That's usually all you need). If you are creating a custom switch, subclass &lt;code&gt;UISwitch&lt;/code&gt; (lols, just kidding. &lt;code&gt;UISwitch&lt;/code&gt; is a terrible and fragile class to subclass. Write your own switch if you need something custom). &lt;/p&gt;
&lt;p&gt;I see so many developers implementing complex touch event listeners in their &lt;code&gt;UIView&lt;/code&gt; subclasses or a needless delegate protocol when they could have just gotten the same behavior for free by using the proper superclass. &lt;/p&gt;
&lt;h2&gt;Use UIViewAutoResizingMask&lt;/h2&gt;
&lt;p&gt;Your first attempt at custom layouts should always use &lt;code&gt;UIViewAutoResizingMask&lt;/code&gt; (this changes in iOS 6.0, read more on &lt;a href="https://developer.apple.com/devcenter/ios/index.action#" title="Apple Developer"&gt;developer.apple.com&lt;/a&gt;). Setting these up takes a trivial amount of time and you stand a pretty good chance of eliminating your custom layout code. Writing flexible and extensible layout code is very hard, which is why most developers don't bother and just hard-code a bunch of magic numbers into their view layouts. Your layout may always be 320px wide today, but someday you're going to enable landscape orientation in your app and having to go back in and debug your layout all over again is going to be a &lt;em&gt;major&lt;/em&gt; headache.&lt;/p&gt;
&lt;h2&gt;Override layoutSubviews&lt;/h2&gt;
&lt;p&gt;Realistically speaking, you're probably going to have layouts that springs and struts can't handle. If you need to do custom layouts, do them in the correct location, by overriding &lt;code&gt;layoutSubviews&lt;/code&gt;. You should always put your layout code in this method. Here's some great reasons why you should be doing this.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;layoutSubviews&lt;/code&gt; will only be called once per run-loop. You can call &lt;code&gt;[self setNeedsLayout]&lt;/code&gt; as much as you want without worrying about taking a performance hit laying out your views needlessly.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;layoutSubviews&lt;/code&gt; is common knowledge. Other developers (and yourself in 6 months) should know to look here for layout code. No need to try and scan unfamiliar code to find the method doing layout; it's always the same one.&lt;/li&gt;
&lt;li&gt;Putting all your layout in one method makes handling state changes much more robust. &lt;a href="http://weblog.bignerdranch.com/769-a-rule-of-thumb-for-controller-code/" title="A Rule of Thumb For Controller Code"&gt;Big Nerd Ranch&lt;/a&gt; has a writeup you should read.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It's fairly common to have your layout depend on the properties of your subviews. This is how people tend to handle layout and it's &lt;strong&gt;wrong&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setDeleteButtonVisible:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BOOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;visible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_visible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;_visible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// move some stuff around to make room for this button&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// move stuff around to cover the empty space&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// where the delete button was&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The biggest issue with doing this is that it scatters your layout code all over your class. Once you get two, three, four or more properties that influence your layout, each property setter becomes an incomprehensible mess of layout code. &lt;strong&gt;Don't do this&lt;/strong&gt;. A much better way to handle property-based layouts is to override &lt;code&gt;layoutSubviews&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setDeleteButtonHidden:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BOOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;hidden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setNeedsLayout&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;layoutSubviews&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;layoutSubviews&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// layout for hidden delete button&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// layout for visible delete button&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can feel free to call &lt;code&gt;[self setNeedsLayout]&lt;/code&gt; as much as you want, those calls will be consolidated and the layout methods will only be called once per run loop. For complex layouts, this can be a massive performance win.&lt;/p&gt;
&lt;h2&gt;Override sizeThatFits:&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;- (CGSize)sizeThatFits:(CGSize)size&lt;/code&gt; is the unsung hero of custom &lt;code&gt;UIView&lt;/code&gt; subclasses. This method can be used to set minimum sizes, maximum sizes, and optimal sizes. The trick here is that the &lt;code&gt;UIView&lt;/code&gt; method &lt;code&gt;sizeToFit&lt;/code&gt; calls through to &lt;code&gt;sizeThatFits:&lt;/code&gt; with the current size, then resizes the view based on the response. &lt;code&gt;sizeToFit:&lt;/code&gt; is always the method that you should override, it's the designated initializer of sizing methods. A great use for this method is to allow users to initialize your class with a zero sized rect while still maintaining a proper frame.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;initWithFrame:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGRect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;frame&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;initWithFrame&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sizeToFit&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;sizeThatFits:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kMinWidth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kMinWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kMinHeight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kMinHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, if someone really wants to initialize your view to an absurd size you can prevent this by overriding &lt;code&gt;setFrame:&lt;/code&gt;, but in my experience, when someone resizes something to the wrong size, it's obvious what they did wrong. When they're attempting to resize something and it just won't become the correct size, it's usually a mystery why. Don't surprise your users, let them shoot themselves in the foot, but make it obvious that they are shooting themselves in the foot.&lt;/p&gt;
&lt;h2&gt;Respond intelligently to weird frame sizes&lt;/h2&gt;
&lt;p&gt;If your &lt;code&gt;UIView&lt;/code&gt; is instantiated by calling &lt;code&gt;init&lt;/code&gt;, the default implementation will call through to &lt;code&gt;initWithFrame:&lt;/code&gt; and pass &lt;code&gt;CGRectZero&lt;/code&gt;. This is very common, and it shouldn't cause your view to blow up or completely break. If you have a minimum size that your control should be, resize yourself in &lt;code&gt;initWithFrame&lt;/code&gt;. If you don't have a minimum size, make sure your subviews are pinned to the correct edges of your bounding rect so that they behave correctly when your view is resized. These two views should both have the same frame and be layed out identically:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;CGRect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Declared to be something reasonable&lt;/span&gt;
&lt;span class="n"&gt;MyCustomView&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;view1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;MyCustomView&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;initWithFrame&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;MyCustomView&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;view2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;MyCustomView&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;view2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A &lt;code&gt;UIView&lt;/code&gt; that blows up when instantied with a size zero frame is a perpetual source of developer annoyance. Don't do this. If you need to use default frame sizes, provide an initializer that doesn't take a frame as a parameter, and override &lt;code&gt;initWithFrame:&lt;/code&gt; to ignore the input frame size. Make a note in the documentation to this effect.&lt;/p&gt;
&lt;h2&gt;Override pointInside:withEvent:&lt;/h2&gt;
&lt;p&gt;The default behavior of &lt;code&gt;pointInside:withEvent:&lt;/code&gt; returns YES if the point is within your bounds. Override this method if your shape does not completely fill its bounds. For example, if you have a button with a transparent center region, you may not want to respond to taps in that region. Override this method to return NO for any points within that transparent area.&lt;/p&gt;
&lt;p&gt;Even more useful, if you have a control that is smaller than the Apple HIG recommended guidelines of 44x44px, you can respond to touches &lt;em&gt;outside&lt;/em&gt; your bounds, effectively increasing the tap target for a given button.&lt;/p&gt;
&lt;h2&gt;Don't override drawRect:&lt;/h2&gt;
&lt;p&gt;Overriding &lt;code&gt;drawRect:&lt;/code&gt; causes a performance hit. I haven't profiled it, so I don't know if it's a signifigant performance under normal circumstances (it's probably not), but in most cases, folks who override &lt;code&gt;drawRect:&lt;/code&gt; can accomplish what they want much easier by setting properties on a view's layer property. If you need to draw an outline around a view, here's how you would do it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#import &amp;lt;QuartzCore/QuartzCore.h&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;initWithFrame:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGRect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;frame&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;initWithFrame&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borderWidth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borderColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;UIColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;redColor&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;CGColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Learning how to properly subclass &lt;code&gt;UIView&lt;/code&gt; will save you a lot of coding, a lot of debugging and will make it much easier for future maintainers of your code to read and understand what you've done, arguably the most important consideration for a developer.&lt;/p&gt;</content><category term="development"></category></entry><entry><title>Sensational.ist</title><link href="https://jimkubicek.com/sensationalist.html" rel="alternate"></link><published>2012-10-02T08:18:00-07:00</published><updated>2012-10-02T08:18:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-10-02:/sensationalist.html</id><summary type="html">&lt;p&gt;This is my million dollar idea. The idea is called "Sensational.ist". Install an extension in your browser. Whenever you read a news article that is full of sensationalist nonsense, trigger the extension. If enough people have labeled an article as sensationalist, all new visiters will see a warning page …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is my million dollar idea. The idea is called "Sensational.ist". Install an extension in your browser. Whenever you read a news article that is full of sensationalist nonsense, trigger the extension. If enough people have labeled an article as sensationalist, all new visiters will see a warning page.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Caution: This article is complete bullshit.&lt;/p&gt;
&lt;p&gt;This article was likely written with a goal of being confrontational to drum up pageviews and advertising dollars. By visiting this site you are supporting the fucks that are ruining online journalism. Please don't visit this page. Rest assured that whatever meager content that was there is utter nonsense and by avoiding it you are helping to get that ass goblin fired.&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="ideas"></category></entry><entry><title>Sort Obj-C Methods with Automator</title><link href="https://jimkubicek.com/sort-obj-c-methods-with-automator.html" rel="alternate"></link><published>2012-09-20T20:56:00-07:00</published><updated>2012-09-20T20:56:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-09-20:/sort-obj-c-methods-with-automator.html</id><summary type="html">&lt;p&gt;Big view controllers in big projects tend to accumulate a &lt;em&gt;lot&lt;/em&gt; of private methods and properties. In a perfect world, these methods and properties should be carefully organized into functional groups and carefully documented. In the world we actually live in, that shit doesn't happen, which is why I've resigned …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Big view controllers in big projects tend to accumulate a &lt;em&gt;lot&lt;/em&gt; of private methods and properties. In a perfect world, these methods and properties should be carefully organized into functional groups and carefully documented. In the world we actually live in, that shit doesn't happen, which is why I've resigned myself to organizing everything alphabetically. &lt;/p&gt;
&lt;p&gt;To make my life easier, I created an automator service that sorts everything for me. Here's how you create it yourself:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Automator.app&lt;/li&gt;
&lt;li&gt;Create a new workflow and select "Service"&lt;/li&gt;
&lt;li&gt;Drag the "Run Shell Script" workflow into the workflow pane.&lt;/li&gt;
&lt;li&gt;Above the workflow, change the drop downs to read "Service recives selected &lt;strong&gt;text&lt;/strong&gt; in &lt;strong&gt;Xcode&lt;/strong&gt;" and check the "Output replaces selected text" box.&lt;/li&gt;
&lt;li&gt;Change the shell drop down to "/usr/bin/ruby"&lt;/li&gt;
&lt;li&gt;Paste &lt;a href="https://gist.github.com/3759637"&gt;the gist below&lt;/a&gt; into the text view.&lt;/li&gt;
&lt;li&gt;Save the service with an appropriate name and you're done!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;{% gist 3759637 %}&lt;/p&gt;
&lt;p&gt;Keep in mind that any comments need to be inline and all method names need to be on one line, no splitting accross multiple lines. I'm not too concerned about this, as it fits my style (I have word wrap turned on) and since nobody &lt;em&gt;ever&lt;/em&gt; reads comments on declarations in the &lt;code&gt;.m&lt;/code&gt; file anyway. When I get a chance I'd like to update this to clean up property declarations (all the names at the same tab-stop) and remove extraneous spacing in method declarations.&lt;/p&gt;</content><category term="development"></category><category term="obj-c"></category></entry><entry><title>Open sourcing? Eliminate all warnings</title><link href="https://jimkubicek.com/open-sourcing-eliminate-all-warnings.html" rel="alternate"></link><published>2012-09-06T22:22:00-07:00</published><updated>2012-09-06T22:22:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-09-06:/open-sourcing-eliminate-all-warnings.html</id><summary type="html">&lt;p&gt;A few months ago Matt Gemmell created a &lt;a href="http://mattgemmell.com/2012/05/24/api-design/"&gt;fantastic writeup&lt;/a&gt; on creating open-source components. One salient point he missed, though, is that you &lt;em&gt;must&lt;/em&gt; compile and test your code with the strictest warnings available. You never know who's going to be using your code and what warnings they have enabled …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few months ago Matt Gemmell created a &lt;a href="http://mattgemmell.com/2012/05/24/api-design/"&gt;fantastic writeup&lt;/a&gt; on creating open-source components. One salient point he missed, though, is that you &lt;em&gt;must&lt;/em&gt; compile and test your code with the strictest warnings available. You never know who's going to be using your code and what warnings they have enabled. Assume the worst, and turn on nearly every warning you can in your project. &lt;a href="http://boredzo.org/blog/archives/2009-11-07/warnings"&gt;Peter Hosey's list&lt;/a&gt; is a great start (there's even &lt;a href="http://rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scpt"&gt;some AppleScript&lt;/a&gt; to automate turning on all these warnings). If you'd like to be extra cautious, use the &lt;code&gt;-Weverything&lt;/code&gt; flag in Clang to turn on all the warnings.&lt;/p&gt;</content><category term="development"></category></entry><entry><title>Having trouble with Adium and iMessage?</title><link href="https://jimkubicek.com/having-trouble-with-adium-and-imessage.html" rel="alternate"></link><published>2012-08-28T15:24:00-07:00</published><updated>2012-08-28T15:24:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-08-28:/having-trouble-with-adium-and-imessage.html</id><summary type="html">&lt;p&gt;I exclusively use Apple's iMessage for chat. Most of my coworkers use Adium. Ever since I started this job there have been weird issues were coworkers can't see me online and don't respond when I message them. I've confirmed that they are not actually getting the messages (and they aren't …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I exclusively use Apple's iMessage for chat. Most of my coworkers use Adium. Ever since I started this job there have been weird issues were coworkers can't see me online and don't respond when I message them. I've confirmed that they are not actually getting the messages (and they aren't quietly hellbanning me). &lt;/p&gt;
&lt;p&gt;Also, the name of my lapop is the Emoji characters 🐒💨.&lt;/p&gt;
&lt;p&gt;Also, your default location in iMessage is the name of your computer.&lt;/p&gt;
&lt;p&gt;Turns out there's a bug in either iMessage, Google Chat or Adium (probably Adium, since iMessage &amp;lt;-&amp;gt; Google Chat works just fine) where Emoji characters in your location cause you to not be visible in Adium. I changed my location to something more vanilla and now all my coworkers can see me online. Hooray!&lt;/p&gt;</content><category term="misc"></category></entry><entry><title>Configure git to only push current branch</title><link href="https://jimkubicek.com/configure-git-to-only-push-current-branch.html" rel="alternate"></link><published>2012-08-16T09:10:00-07:00</published><updated>2012-08-16T09:10:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-08-16:/configure-git-to-only-push-current-branch.html</id><summary type="html">&lt;p&gt;I've always used plain &lt;code&gt;git push&lt;/code&gt; to update my remote repos and I'm finally getting tired of seeing this error every time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="nv"&gt;@github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;jkubicek&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;my_proj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="n"&gt;b430d&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;dd378ca&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rejected&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;some&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;refs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I've always used plain &lt;code&gt;git push&lt;/code&gt; to update my remote repos and I'm finally getting tired of seeing this error every time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="nv"&gt;@github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;jkubicek&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;my_proj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="n"&gt;b430d&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;dd378ca&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;master&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rejected&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;some&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;refs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git@github.com:jkubicek/my_proj.git&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Updates&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;were&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rejected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;because&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pushed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;behind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;its&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counterpart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;did&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;intend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;may&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;specify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branches&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;push.default&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nl"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;variable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;current&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;upstream&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I can only blame this on my utter laziness, because the answer is right in the error text. Run the following command to configure &lt;code&gt;git push&lt;/code&gt; to only push your current branch.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git config --global push.default current
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I should have done this months ago.&lt;/p&gt;</content><category term="development"></category></entry><entry><title>Don't Lazily Load Your Views</title><link href="https://jimkubicek.com/dont-lazily-load-your-views.html" rel="alternate"></link><published>2012-08-09T11:11:00-07:00</published><updated>2012-08-09T11:11:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-08-09:/dont-lazily-load-your-views.html</id><summary type="html">&lt;p&gt;I seem to run accross a lot of developers lazily loading their properties. As an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;UILabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="bp"&gt;UILabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addSubview&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At least in iOS developement, I suspect this is caused by Apple's sample code, particularly Apple's default setup for Core Data projects …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I seem to run accross a lot of developers lazily loading their properties. As an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;UILabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="bp"&gt;UILabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addSubview&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At least in iOS developement, I suspect this is caused by Apple's sample code, particularly Apple's default setup for Core Data projects. There are some valid reasons why you'd want to lazily load a resources, but there's lots of great reasons why you shouldn't. Here's a few:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Property calls should not have side effects&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are lots of exceptions for setters (like updating the UI after setting a property), but there are very few exceptions for getters. You shouldn't need to worry about your object changing state when you access a property.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lazy loading is confusing&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myTextLabel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@&amp;quot;What the shit? How did I get here?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Lazy loading leads to tricky initialization order dependences&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;UILabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="bp"&gt;UILabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myTitle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sizeToFit&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addSubview&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_myTextLabel&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now your label will have different text depending on whether you set &lt;code&gt;myTitle&lt;/code&gt; before or after you access &lt;code&gt;myTextLabel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lazy loading leads weird code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;.&lt;span class="nv"&gt;myTextLabel&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;setup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;my&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Initialization, layout, UI updates should be localized&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You should be performing all initialization in the init method, UI updates in an update UI method and layout in &lt;code&gt;layoutSubviews&lt;/code&gt;. Not only does this make debugging far easier (having layout issues? I feel bad for you, son. I've got 99 problems, but performing view layout anywhere other than &lt;code&gt;layoutSubviews&lt;/code&gt; isn't one.), but it ensures that your view is always in a consistent state. &lt;a href="http://weblog.bignerdranch.com/769-a-rule-of-thumb-for-controller-code/" title="A Rule of Thumb For Controller Code"&gt;Big Nerd Ranch&lt;/a&gt; has a great writeup on why this is important.&lt;/p&gt;
&lt;p&gt;Clearly there are exceptions to all these rules and situations where lazily loading your view properties is the right thing to do. But remember, always write code that emphasizes clarity first and optimize for speed or memory constraints later. &lt;/p&gt;</content><category term="development"></category></entry><entry><title>OK. For serious this time</title><link href="https://jimkubicek.com/ok-for-serious-this-time.html" rel="alternate"></link><published>2012-07-18T22:19:00-07:00</published><updated>2012-07-18T22:19:00-07:00</updated><author><name>Jim Kubicek</name></author><id>tag:jimkubicek.com,2012-07-18:/ok-for-serious-this-time.html</id><summary type="html">&lt;p&gt;OK. This is a fresh start. I think I've got this blogging thing figured out for once. I'm using &lt;a href="http://octopress.org" title="Octopress"&gt;Octopress&lt;/a&gt; to create the site. I attempted to install Octopress a few months ago, but ran into a whole host issues trying to get ruby 1.9.2 to build. Luckily …&lt;/p&gt;</summary><content type="html">&lt;p&gt;OK. This is a fresh start. I think I've got this blogging thing figured out for once. I'm using &lt;a href="http://octopress.org" title="Octopress"&gt;Octopress&lt;/a&gt; to create the site. I attempted to install Octopress a few months ago, but ran into a whole host issues trying to get ruby 1.9.2 to build. Luckily, Ruby 1.9.3 seems to fix all my issues, and installed smooth as silk. I never really got a chance to use Octopress 1.x, but 2.0 is going great. Here's what I wanted in a blogging platform.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pre-rendered HTML pages&lt;/strong&gt; I don't have any illusions about the amount of traffic I'll be getting, so performance isn't that a concern for me. I do want to avoid the "black box" of PHP and MySQL that I'd been used to with Wordpress. The chances of me learning every little detail of the blogging platform are slim, but if I do decide to dive in, I want it to be as easy and as frictionless as possible. Octopress is just a bunch of scripts. Nothing sneaky there!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Easy to modify&lt;/strong&gt; A little bit of HTML, a bit of javascript, maybe a little ruby. Writing themes and modifying the behavior of the site is something well within my reach.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run the site locally&lt;/strong&gt; Right out of the box, Octopress makes it easy to get a full version of your site served locally. Try that, Wordpress!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Text only input&lt;/strong&gt; I want to be able to write a blog post from anywhere on any device. Having plain text input ensures that I'll have no excuses if I want to get something written. Plus, if I need to search my entries or make bulk changes, I've got my command line tools right here. Oh, and shit, I can also sit in coffee shops running full-screen Vim (green text on black background) to look like an &amp;uuml;ber-hacker.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Good code formatting&lt;/strong&gt; I'd like to make this a mostly develpment blog. Good code formatting is important. Easy code formatting is just as important.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Most importantly, I've got a pretty sizeable chunck of writing saved up and ready to deploy. I'm hoping I can just throw these files in my favorite text editor and hit "publish". I'm sure a few will get thrown out in the editing process, but I'm hoping that I use those first few posts to build up some intertia.&lt;/p&gt;
&lt;p&gt;Let's see where this takes us! &lt;/p&gt;</content><category term="personal"></category></entry></feed>