The blog of Christopher2019-08-23T14:40:52+00:00http://www.codeography.comChristopherchris@codeography.comInstalling Rails 6 on Heroku Revisited2019-08-22T00:00:00+00:00http://www.codeography.com/2019/08/22/rails-6-on-heroku-revisited<p>In my <a href="/2019/08/02/rails-6-on-heroku.html">original post</a> I outlined a solution that involved adding a Heroku build pack. But after a discussion on <a href="https://github.com/rails/webpacker/pull/2206"><code class="highlighter-rouge">rails/webpacker</code></a> found a better way to handle this error.</p>
<p>So if you see this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Compilation failed:
!
! Precompiling assets failed.
!
! Push rejected, failed to compile Ruby app.
! Push failed
</code></pre></div></div>
<p>I was able to fix the issue by moving the sass packages into the production dependencies instead of the <code class="highlighter-rouge">devDependencies</code></p>
<p>I moved the two Sass packages to <code class="highlighter-rouge">dependencies</code>, and it worked:</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code> "dependencies": {
"@rails/actioncable": "^6.0.0",
"@rails/activestorage": "^6.0.0",
"@rails/ujs": "^6.0.0",
"@rails/webpacker": "^4.0.2",
"turbolinks": "^5.2.0",
<span class="gi">+ "node-sass": "^4.12.0",
+ "sass-loader": "^7.1.0"
</span> },
"devDependencies": {
<span class="gd">- "node-sass": "^4.12.0",
- "sass-loader": "^7.1.0",
</span> "webpack-dev-server": "^3.3.1"
},
</code></pre></div></div>
<p>This winds up being a better solution because:</p>
<ol>
<li>It doesn’t rerun the yarn install (which can take a while, <a href="https://github.com/rails/webpacker/pull/2206#issuecomment-519980678">even if it is supposed to be fast on subsuquent runs</a>)</li>
<li>Uses the libraries I expected</li>
<li>Works with the default Heroku buildpack</li>
</ol>
<p>Thanks to <a href="https://github.com/bbugh">Brian</a> and <a href="https://github.com/jakeNiemiec">Jake</a> for helping me get this sorted. Still a learning process with NPM, Webpack, and friends.</p>
Installing Rails 6 on Heroku2019-08-02T00:00:00+00:00http://www.codeography.com/2019/08/02/rails-6-on-heroku<hr />
<h1 id="update-there-is-a-better-way">Update: there is a better way!</h1>
<p>After some discussion on the <code class="highlighter-rouge">rails/webpacker</code> issues I have a better solution for this. See the <a href="/2019/08/22/rails-6-on-heroku-revisited.html">updated post</a> for details.</p>
<hr />
<p>Ran into a problem installing Rails 6.0.0.rc2 on Heroku. Being a good Rails citizen I was trying use Webpacker and all it’s JS goodness.</p>
<p>Then I spent two days trying to figure out why assets wouldn’t compile when deploying to heroku. And I got this frustratingly vague error:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Compilation failed:
!
! Precompiling assets failed.
!
! Push rejected, failed to compile Ruby app.
! Push failed
</code></pre></div></div>
<p>After some digging I <a href="https://github.com/rails/webpacker/blob/master/docs/troubleshooting.md#compilation-fails-silently">found out</a> you can enable errors in Webpacker by editing <code class="highlighter-rouge">config/webpacker.yml</code>:</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gd">- webpack_compile_output: false
</span><span class="gi">+ webpack_compile_output: true
</span></code></pre></div></div>
<p>Which showed errors (yay!):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ERROR in ./app/javascript/theme/style.scss (./node_modules/css-loader/dist/cjs.js??ref--7-1!./node_modules/postcss-loader/src??ref--7-2!./node_modules/sass-loader/lib/loader.js??ref--7-3!./app/javascript/theme/style.scss)
Module build failed (from ./node_modules/sass-loader/lib/loader.js):
Error: ENOENT: no such file or directory, scandir '/tmp/build_b6d942494af54889b656091b0e3a440f/node_modules/node-sass/vendor'
</code></pre></div></div>
<p>See <a href="https://gist.github.com/csexton/7872e358e4d4294d9dffd489ca31b49c">this gist</a> for the full log.</p>
<p>Turns out this is due to a strange bug with node-sass where it needs to be re-built after updating modules. The <a href="https://help.heroku.com/LRB0A1Q8/why-are-my-builds-failing-with-a-node-sass-error">solution</a> is is to add a postinstall script to your <code class="highlighter-rouge">package.json</code>:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"postinstall"</span><span class="p">:</span><span class="w"> </span><span class="s2">"npm rebuild node-sass"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Cool, thought this would fix it. But still got the same error above. When I connected to a bash terminal in teh heroku console I found a weird error:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ $ npm rebuild node-sass
bash: npm: command not found
</code></pre></div></div>
<p>Wut? I thougth node was part of the <a href="https://github.com/heroku/heroku-buildpack-ruby">Ruby build pack</a> on Heroku. Turns out, we <a href="https://github.com/rails/webpacker/issues/395#issuecomment-302024296">need</a> the <a href="https://github.com/heroku/heroku-buildpack-nodejs">Node.js buildpack</a> to get a <code class="highlighter-rouge">npm</code> binary.</p>
<p>So I added the buildpack, making sure to put the node one earlier in the list.</p>
<p><img src="/images/rails6-heroku.png" alt="Node.js build pack on Heroku dashboard" /></p>
<p>Then I got a sweet green “Build Succeeded” message in Heroku.</p>
<p><img src="/images/rails6-heroku-build.png" alt="Build Succeeded on Heroku dashboard" /></p>
Get the pull request number from the branch2018-10-30T00:00:00+00:00http://www.codeography.com/2018/10/30/get-the-pull-request-number-from-the-branch<p>So started trying out Heroku CI and discovered it was missing a few things I had grown accustomed to with Travis. Most recently it didn’t have the Pull Request number in an environment variable like Travis’s <code class="highlighter-rouge">TRAVIS_PULL_REQUEST</code></p>
<p>So, I needed to get the GitHub Pull Request number from the branch name.</p>
<p>Turns out you can pull this off with the API fairly easily.</p>
<p>If I wanted to use the <a href="https://github.com/octokit/octokit.rb">Octokit</a> gem:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s1">'bundler/inline'</span>
<span class="n">gemfile</span> <span class="k">do</span>
<span class="n">source</span> <span class="s1">'https://rubygems.org'</span>
<span class="n">gem</span> <span class="s1">'octokit'</span>
<span class="n">gem</span> <span class="s1">'pry'</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">find_pr</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span>
<span class="n">client</span> <span class="o">=</span> <span class="no">Octokit</span><span class="o">::</span><span class="no">Client</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">:access_token</span> <span class="o">=></span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'GITHUB_ACCESS_TOKEN'</span><span class="p">])</span>
<span class="n">client</span><span class="p">.</span><span class="nf">pull_requests</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="p">{</span><span class="ss">head: </span><span class="n">branch</span><span class="p">}).</span><span class="nf">first</span><span class="o">&</span><span class="p">.</span><span class="nf">number</span>
<span class="k">end</span>
<span class="c1"># Find the pull request number on the csexton/codeography.com repo</span>
<span class="c1"># for 'my-branch':</span>
<span class="nb">puts</span> <span class="n">find_pr</span><span class="p">(</span><span class="s1">'csexton/codeography.com'</span><span class="p">,</span> <span class="s1">'csexton:my-branch'</span><span class="p">)</span>
</code></pre></div></div>
<p>But it would be nice to have no dependencies, and could skip that bundler install overhead:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s2">"net/https"</span>
<span class="nb">require</span> <span class="s2">"uri"</span>
<span class="nb">require</span> <span class="s2">"json"</span>
<span class="k">def</span> <span class="nf">find_pr</span><span class="p">(</span><span class="n">org</span><span class="p">,</span> <span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span>
<span class="n">uri</span> <span class="o">=</span> <span class="no">URI</span><span class="p">(</span><span class="s2">"https://api.github.com/repos/</span><span class="si">#{</span><span class="n">org</span><span class="si">}</span><span class="s2">/</span><span class="si">#{</span><span class="n">repo</span><span class="si">}</span><span class="s2">/pulls?head=</span><span class="si">#{</span><span class="n">org</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="n">http</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="nf">host</span><span class="p">,</span> <span class="n">uri</span><span class="p">.</span><span class="nf">port</span><span class="p">)</span>
<span class="n">http</span><span class="p">.</span><span class="nf">use_ssl</span> <span class="o">=</span> <span class="kp">true</span>
<span class="n">request</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">Get</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">.</span><span class="nf">request_uri</span><span class="p">)</span>
<span class="n">request</span><span class="p">[</span><span class="s1">'Authorization'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"token </span><span class="si">#{</span><span class="no">ENV</span><span class="p">[</span><span class="s1">'GITHUB_ACCESS_TOKEN'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">http</span><span class="p">.</span><span class="nf">request</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
<span class="n">json</span> <span class="o">=</span> <span class="no">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="nf">body</span><span class="p">)</span>
<span class="k">if</span> <span class="n">json</span><span class="p">.</span><span class="nf">count</span> <span class="o">==</span> <span class="mi">1</span>
<span class="n">json</span><span class="p">.</span><span class="nf">first</span><span class="p">[</span><span class="s2">"number"</span><span class="p">]</span>
<span class="k">else</span>
<span class="kp">nil</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="n">find_pr</span><span class="p">(</span><span class="s1">'csexton/codeography.com'</span><span class="p">,</span> <span class="s1">'csexton:my-branch'</span><span class="p">)</span>
</code></pre></div></div>
<p>Code is uglier (thanks Net::HTTP), but it just uses the standard library.</p>
The Next Era of Remapping Caps Lock2017-07-16T00:00:00+00:00http://www.codeography.com/2017/07/16/the-next-era-of-remapping-caps-lock<p>I had previously <a href="/2010/12/02/remap-capslock-to-control-on-a-mac.html">written</a> about <a href="/2013/06/26/remapping-caps-lock-was-only-the-beginning.html">remapping</a> parts of the keyboard, but most of those techniques had stopped working as Apple continued to evolve the Mac.</p>
<p>The latest generation of Apple products was threatening my precious keyboard control. The TouchBar on make <code class="highlighter-rouge">esc</code> an awkward virtual key, and macOS Sierra broke Karabiner. It was a little rough there for a while. Shortly after Sierra was released Takayama Fumihiko created the <a href="https://github.com/tekezo/Karabiner-Elements">Karabiner-Elements</a> project, but it lacked much of the functionality of the original. Necessary step back to move forward, but no fun.</p>
<p>But that is all a thing of the past, the new era has arrived. Karabiner-Elements now supports complex rules.</p>
<h3 id="magic-mapping-1-caps-lock">Magic Mapping #1: Caps Lock</h3>
<p>The most important complex rule for me, especially for any Mac with a TouchBar, is the dual function <code class="highlighter-rouge">caps_lock</code> key.</p>
<ol>
<li>Act like <code class="highlighter-rouge">control</code> when pressed with any other key. So if you use it in a chord it will just be control, e.g. <code class="highlighter-rouge">control-c</code> but with the Caps lock key.</li>
<li>Act like <code class="highlighter-rouge">esc</code> if you press and release the key. So if you just tap the key it will send <code class="highlighter-rouge">esc</code>.</li>
</ol>
<h3 id="magic-mapping-2-vim-arrows">Magic Mapping #2: Vim Arrows</h3>
<p>The other mapping that I love having is <code class="highlighter-rouge">control+h/j/k/l</code> to be the arrow keys. This way I have vim-like navigation in every app. Some apps on Mac already map <code class="highlighter-rouge">control-j/k</code> to <code class="highlighter-rouge">up/down</code>, but if you remap it to the arrows it will just work like you expect everywhere.</p>
<h3 id="how-to-set-up-these-custom-mappings">How to set up these custom mappings</h3>
<p>Karabiner-Elements has a fantastic way to import custom rules. If you have the app installed just click the following link and it will open automatically.</p>
<p><a href="karabiner://karabiner/assets/complex_modifications/import?url=https%3A%2F%2Fraw.githubusercontent.com%2Fcsexton%2Fcsexton.github.com%2Fmaster%2Fkarabiner%2Frules.json">Add Rules to Karabiner</a></p>
<p>You will see a confirmation asking you to open it in the app:</p>
<p><img src="/images/karabiner-1.png" alt="Confirmation Dialog" /></p>
<p>It will confirm the rules you are importing:</p>
<p><img src="/images/karabiner-2.png" alt="Import Dialog" /></p>
<p>Then give you the option to add the ones you want.</p>
<p><img src="/images/karabiner-3.png" alt="Karabiner Complex Rules" /></p>
<p>Let me know if this is helpful, or if you have slightly different configurations you prefer.</p>
Migrate ActiveRecord column to an hstore key in Rails2016-11-15T00:00:00+00:00http://www.codeography.com/2016/11/15/migrate-active-record-column-to-hstore<p>I really do like <a href="https://www.postgresql.org/docs/current/static/hstore.html">PostgreSQL’s <code class="highlighter-rouge">hstore</code> type</a>, espcially when I have some configuration properties that I don’t need to query or index. But ran into a problem when I needed to migrate data. I needed to move a column to an hstore within the same row (and back again).</p>
<p>Knowing that migrating data with ruby models is fragile and WILL break when you change your models – I wanted the data munging to be done in raw SQL.</p>
<p>Say I have a <code class="highlighter-rouge">url</code> column in <code class="highlighter-rouge">my_table</code>. I want to move that to the ‘url’ key in a new <code class="highlighter-rouge">hstore</code> column called (helpfully) <code class="highlighter-rouge">my_hstore</code>. This migration will add the new column, migrate the data and drop the old column. If nervous about that and want to keep the column around just delete the <code class="highlighter-rouge">remove_column</code> bit.</p>
<p>First, generate the migration:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails generate migration move_url_to_my_hstore
</code></pre></div></div>
<p>Then, update it to add the column, migrate the data, and drop the column. Then reverse the entire process in the <code class="highlighter-rouge">down</code> method:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MoveUrlToMyHstore</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">5.0</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">up</span>
<span class="n">add_column</span> <span class="ss">:my_table</span><span class="p">,</span> <span class="ss">:my_hstore</span><span class="p">,</span> <span class="ss">:hstore</span>
<span class="n">execute</span> <span class="o"><<~</span><span class="no">END</span><span class="sh">
UPDATE my_table
SET my_hstore = hstore('url', subquery.url)
FROM (SELECT id, url FROM my_table) as subquery
WHERE my_table.id=subquery.id;
</span><span class="no"> END</span>
<span class="n">remove_column</span> <span class="ss">:my_table</span><span class="p">,</span> <span class="ss">:url</span><span class="p">,</span> <span class="ss">:string</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">down</span>
<span class="n">add_column</span> <span class="ss">:my_table</span><span class="p">,</span> <span class="ss">:url</span><span class="p">,</span> <span class="ss">:string</span>
<span class="n">execute</span> <span class="o"><<~</span><span class="no">END</span><span class="sh">
UPDATE my_table
SET url = subquery.turl FROM (SELECT id, my_hstore->'url' as turl FROM my_table) as subquery
WHERE my_table.id=subquery.id;
</span><span class="no"> END</span>
<span class="n">remove_column</span> <span class="ss">:my_table</span><span class="p">,</span> <span class="ss">:my_hstore</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Hope this is helpful to someone out there.</p>
Multiple SSL endpoints on Heroku with SNI2016-11-07T00:00:00+00:00http://www.codeography.com/2016/11/07/multiple-ssl-endpoints-on-heroku-with-sni<p>I recently added another domain to an app I host on Heroku. And I ran into a problem:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Only one SNI endpoint is allowed per app (try certs:update instead).
</code></pre></div></div>
<p>You can’t have more than one cert on a SNI endpoint. Turns out you don’t need more than one cert. You just need a Multi-Domain cert.</p>
<p>Luckily you can get one pretty easily, as long as you know a few tricks to set it up. I got to admit I was a little worried about the manual steps for setting up the openssl config and CSR, but it was worth risking $25 to save $360/year in SSL endpoints on heroku. Turns out this even works with wildcards.</p>
<h3 id="1-buy-multi-domain-ssl-cert">1. Buy Multi-Domain SSL Cert</h3>
<p>I bought a “Comodo PositiveSSL Multi-Domain” from <a href="https://www.ssls.com/ssl-certificates/comodo-positivessl-multi-domain">SSLs.com</a>. Buy it first, and you will add the domains and “Activate” it later.</p>
<h3 id="2-create-the-signing-request-csr">2. Create the Signing Request (CSR)</h3>
<p>This is specific to a Mac, but should work on other platforms if you adjust a few paths.</p>
<p>First lets make a folder to put all our files in:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir mydomain_com_multidomain
cd mydomain_com_multidomain
</code></pre></div></div>
<p>Copy the default `openssl.cnf file :</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp /System/Library/OpenSSL/openssl.cnf .
</code></pre></div></div>
<p>Edit that new file, and modify the folling sections:</p>
<p>At the end of the <code class="highlighter-rouge">[ req ]</code> add:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>req_extensions = v3_req
</code></pre></div></div>
<p>At the end of <code class="highlighter-rouge">[ v3_req ]</code> add:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>subjectAltName = @alt_names
[ alt_names ]
DNS.1 = foo.net
DNS.2 = bar.com
DNS.3 = *.baz.com
</code></pre></div></div>
<p>Just enter the domain you want. As you can see this will even work with wildcard domains. Unlike some other certs, you will have to enter seperate domains for “www.foo.com and “foo.com”.</p>
<p>You can see a full example of the file here: <a href="https://gist.github.com/csexton/ca9971f24001bf504181745ec779ca8e"><code class="highlighter-rouge">openssl.cnf</code></a>.</p>
<p>Generate a signing key:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl genrsa -out server.key 2048
</code></pre></div></div>
<p>Generate the CSR:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl req -nodes -newkey rsa:2048 -keyout server.key -out server.csr -config openssl.cnf
</code></pre></div></div>
<p>You’ll be asked a bunch of questions. It’s best to not leave any blank, but as far as I can tell it doesn’t matter much what they are. Entering “NA” is totally acceptable.</p>
<h3 id="3-activate-that-cert">3. Activate that cert</h3>
<p>Back on the browser on SSLs.com. They will ask for your CSR, just copy and paste:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat server.csr | pbcopy
</code></pre></div></div>
<p>Follow their flow, and confirm your domains. Once that’s done they’ll email you a zip file with the certs.</p>
<h3 id="4-bundle-the-certs-into-one-file">4. bundle the certs into one file.</h3>
<p>This is important for some browsers to work, like Chrome.</p>
<p>Unzip the attachemt they emailed you into the dir you created above, then cat the files together. Order is important:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat YOUR_CERT.crt COMODORSADomainValidationSecureServerCA.crt cOMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > multidomain-bundle.pem
</code></pre></div></div>
<h3 id="5-add-the-cert-to-heroku-using-sni">5. Add the cert to Heroku using SNI</h3>
<p>Almost there, just one last step:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku certs:add path/to/multidomain-bundle.pem path/to/server.key
</code></pre></div></div>
<p>Heroku will let you know the domains and DNS setting you’ll need:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== Your certificate has been added successfully. Update your application's DNS settings as follows
Domain Record Type DNS Target
──────────────────────────── ─────────── ──────────────────────────────────────────
foo.bar.com CNAME foo.bar.com.herokudns.com
baz.net ALIAS/ANAME baz.net.herokudns.com
</code></pre></div></div>
<p>Add those to DNS and you should be good. If you already had a cert on your domain you’ll need to remove it first with <code class="highlighter-rouge">heroku certs:remove</code></p>
<hr />
<p>This SSL stuff is turtles all the way down, so hopefully this guide saves you some time.</p>
Fenced codeblocks in unordered lists with Github Flavored Markdown2016-06-24T00:00:00+00:00http://www.codeography.com/2016/06/24/fenced-code-in-github-markdown<p>Turns out you can have fenced code blocks in ordered lists with Github Flavored Markdown. Just the formatting was a little picky.</p>
<ul>
<li>Prefix the line with 4 spaces for every level in the list</li>
<li>Empty lines before and after the code block</li>
</ul>
<p>So that means if the list has only one level just prefix it with 4 spaces:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. First Item
1. Second Item
```
# My codes
```
1. Third Item
</code></pre></div></div>
<p>If it is a nested list</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. First Parent Item
```
# Parent codes
```
1. Second Parent Item
1. First Child Item
```
# Child codes
```
1. Second Child Item
1. Third Parent Item
</code></pre></div></div>
Automatically attach to tmux when connecting via ssh2016-04-30T00:00:00+00:00http://www.codeography.com/2016/04/30/automatically-connect-to-tmux-with-ssh<p>Recently I have needed to keep a long running sessions open on a server. And I have been using <a href="https://tmux.github.io/">tmux</a> for this purpose for quite some time. However, my internet connection has been flaky, so I’ve been dropping the connection very frequently. So I wanted to automate the steps. I also had the requirement that the server would have no custom configuration for tmux.</p>
<p>What I came up with was the following command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -t example.com "tmux attach-session -t chris || tmux new-session -s chris"
</code></pre></div></div>
<ul>
<li>
<p>The <code class="highlighter-rouge">-t</code> option tells ssh to treat the command like a pseudo-terminal, so you can run interactive commands.</p>
</li>
<li>
<p>The two or’d tmux commands will connect to a new session if it exists, or create a new one if it doesn’t.</p>
</li>
</ul>
<p>When I roll that up into a little bash script that will name the session the name of my user on my local machine:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="nb">set</span> <span class="nt">-e</span>
<span class="nv">server</span><span class="o">=</span><span class="nv">$1</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">]</span> <span class="p">;</span> <span class="k">then
</span><span class="nb">echo</span> <span class="s2">"Usage: </span><span class="k">$(</span>basename <span class="nv">$0</span><span class="k">)</span><span class="s2"> hostname [session name]"</span>
<span class="nb">exit </span>1
<span class="k">fi
</span><span class="nv">name</span><span class="o">=</span><span class="nv">$2</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span> <span class="o">]</span> <span class="p">;</span> <span class="k">then
</span><span class="nv">name</span><span class="o">=</span><span class="k">$(</span>whoami<span class="k">)</span>
<span class="k">fi
</span>ssh <span class="nt">-t</span> <span class="nv">$server</span> <span class="s2">"tmux attach-session -t </span><span class="nv">$name</span><span class="s2"> || tmux new-session -s </span><span class="nv">$name</span><span class="s2">"</span>
</code></pre></div></div>
Heroku CLI Environments Wrapper2016-04-27T00:00:00+00:00http://www.codeography.com/2016/04/27/heroku-environments-command-line-helper<p>I was pretty annoyed at this message:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% heroku logs
▸ Error: Multiple apps in git remotes
▸ Usage: heroku logs --remote production
▸ or: heroku logs --app my-app-production
▸
▸ Your local git repository has more than 1 app referenced in git remotes.
▸ Because of this, we can't determine which app you want to run this command against.
▸ Specify the app you want with --app or --remote.
▸
▸ Heroku remotes in repo:
▸ production (my-app-production)
▸ staging (my-app-staging)
▸
▸ https://devcenter.heroku.com/articles/multiple-environments
</code></pre></div></div>
<p>I’d found the <code class="highlighter-rouge">--app</code> flag to the <a href="https://devcenter.heroku.com/articles/heroku-command">Heroku CLI</a> to be a bit cumbersome. In particular using the command history in the terminal to be pretty awkward, plus it made it easier to mix up environment names.</p>
<p>Nearly all of my dozen or so apps hosted on heroku have multiple environments. So I am probably dealing with this more than most folks would. But like a good yak-shaver, any chance I get to automate away an annoyance I go for it.</p>
<p>What I wanted was a command that matched my environment name. Instead of:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku logs --app my-app-production
</code></pre></div></div>
<p>I would use:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>production logs
</code></pre></div></div>
<p>The my solution was a little wrapper script that would look at the git config to find the git remote name, and use that to grab the app name from the git URL and re-write my command to use that as the <code class="highlighter-rouge">--app</code> parameter.</p>
<p>The way this script works is:</p>
<ol>
<li>Inspect the name of the command run, in the above example that would be “production”</li>
<li>Look in the git config for a remote named “production”</li>
<li>Grab the git URL for that remote and take the repo name</li>
<li>Run the <code class="highlighter-rouge">heroku</code> command with that repo name as the name</li>
</ol>
<p>Since I have multiple environment names like “production” and “staging” I install this script and make symlinks to it with those matching names. You could also duplicate it or make copies. So to install it, just copy it locally and symlink it to the appropriate names:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /path/to/bin
curl -O https://raw.githubusercontent.com/csexton/dotfiles/master/bin/heroku-environments
ln -s heroku-enviroments staging
ln -s heroku-enviroments production
</code></pre></div></div>
<p>An just add symlinks for any environment names you might want.</p>
<p>Hope someone else finds this useful. I’ve quickly become addicted to using it.</p>
<p>You can find the lastest and greatest version of <a href="https://github.com/csexton/dotfiles/blob/master/bin/heroku-environments">the <code class="highlighter-rouge">heroku-environments</code> script in my dotfiles</a>, and the version at the time of this writing is availabe in <a href="https://gist.github.com/csexton/a59e3c6b45ecd181c4ad3e7d21463258">this gist</a></p>
Signing AWS API Requests in Swift2016-03-20T00:00:00+00:00http://www.codeography.com/2016/03/20/signing-aws-api-requests-in-swift<p>Previously <a href="http://www.capturedapp.com/">Captured</a> would just post to S3’s REST API directly, but Amazon has decided to deprecate the fairly straightforward HTTP signing they had. So unless you are using region that has support granfathered, you need to use the newer V4 Signing process.</p>
<p>Since the <a href="https://github.com/aws/aws-sdk-ios">AWS SDK for Objective C</a> doesn’t support OS X, I set out to do the singing myself. AWS had pretty good documentation for it, so how hard could this be?</p>
<p>It was way more effort than I expected. This became my White Whale. And spent way too much time on it. Spent hours troubleshooting an extra slash in the request, or having the wrong case for a hexdigest. But I had to win. The kids can make their own dinner, HMAC ain’t gonna authenticate it self.</p>
<p>So I am posting the code here in case it helps someone.</p>
<hr />
<p>See the <a href="http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html">Signature Version 4 Signing Process</a> for the official documentation. Most of this code was carefully, nay, painstakingly <a href="https://github.com/aws/aws-sdk-ios/blob/440d3141/AWSCore/Authentication/AWSSignature.m">ported from ruby</a></p>
<p>A few shortcuts were taken with this (doesn’t handle query params, or strip whitespace from headers), but it is working great in my app with S3.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// S3V4Uploader.swift</span>
<span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">class</span> <span class="kt">S3V4Signer</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">accessKey</span><span class="p">:</span> <span class="kt">String</span>
<span class="k">let</span> <span class="nv">secretKey</span><span class="p">:</span> <span class="kt">String</span>
<span class="k">let</span> <span class="nv">regionName</span><span class="p">:</span> <span class="kt">String</span>
<span class="k">let</span> <span class="nv">serviceName</span><span class="p">:</span> <span class="kt">String</span>
<span class="kd">required</span> <span class="nf">init</span><span class="p">(</span><span class="nv">accessKey</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">secretKey</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">regionName</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">serviceName</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">"s3"</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">accessKey</span> <span class="o">=</span> <span class="n">accessKey</span>
<span class="k">self</span><span class="o">.</span><span class="n">secretKey</span> <span class="o">=</span> <span class="n">secretKey</span>
<span class="k">self</span><span class="o">.</span><span class="n">regionName</span> <span class="o">=</span> <span class="n">regionName</span>
<span class="k">self</span><span class="o">.</span><span class="n">serviceName</span> <span class="o">=</span> <span class="n">serviceName</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">signedHeaders</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">NSURL</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">"PUT"</span><span class="p">,</span> <span class="nv">date</span><span class="p">:</span> <span class="kt">NSDate</span> <span class="o">=</span> <span class="kt">NSDate</span><span class="p">())</span> <span class="o">-></span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">String</span><span class="p">]</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">datetime</span> <span class="o">=</span> <span class="nf">timestamp</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="k">var</span> <span class="nv">headers</span> <span class="o">=</span> <span class="p">[</span>
<span class="s">"x-amz-content-sha256"</span><span class="p">:</span> <span class="n">bodyDigest</span><span class="p">,</span>
<span class="s">"x-amz-date"</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span>
<span class="s">"x-amz-acl"</span> <span class="p">:</span> <span class="s">"public-read"</span><span class="p">,</span>
<span class="s">"Host"</span><span class="p">:</span> <span class="n">url</span><span class="o">.</span><span class="n">host</span><span class="o">!</span><span class="p">,</span>
<span class="p">]</span>
<span class="n">headers</span><span class="p">[</span><span class="s">"Authorization"</span><span class="p">]</span> <span class="o">=</span> <span class="nf">authorization</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="n">headers</span><span class="p">,</span> <span class="nv">datetime</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="n">httpMethod</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="n">bodyDigest</span><span class="p">)</span>
<span class="k">return</span> <span class="n">headers</span>
<span class="p">}</span>
<span class="c1">// MARK: Utilities</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">pathForURL</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">NSURL</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">path</span> <span class="o">=</span> <span class="n">url</span><span class="o">.</span><span class="n">path</span>
<span class="k">if</span> <span class="p">(</span><span class="n">path</span> <span class="p">??</span> <span class="s">""</span><span class="p">)</span><span class="o">.</span><span class="n">isEmpty</span> <span class="p">{</span>
<span class="n">path</span> <span class="o">=</span> <span class="s">"/"</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">path</span><span class="o">!</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">sha256</span><span class="p">(</span><span class="nv">str</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="n">str</span><span class="o">.</span><span class="nf">dataUsingEncoding</span><span class="p">(</span><span class="kt">NSUTF8StringEncoding</span><span class="p">)</span><span class="o">!</span>
<span class="k">var</span> <span class="nv">hash</span> <span class="o">=</span> <span class="p">[</span><span class="kt">UInt8</span><span class="p">](</span><span class="nv">count</span><span class="p">:</span> <span class="kt">Int</span><span class="p">(</span><span class="kt">CC_SHA256_DIGEST_LENGTH</span><span class="p">),</span> <span class="nv">repeatedValue</span><span class="p">:</span> <span class="mi">0</span><span class="p">)</span>
<span class="kt">CC_SHA256</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">bytes</span><span class="p">,</span> <span class="kt">CC_LONG</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">length</span><span class="p">),</span> <span class="o">&</span><span class="n">hash</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">res</span> <span class="o">=</span> <span class="kt">NSData</span><span class="p">(</span><span class="nv">bytes</span><span class="p">:</span> <span class="n">hash</span><span class="p">,</span> <span class="nv">length</span><span class="p">:</span> <span class="kt">Int</span><span class="p">(</span><span class="kt">CC_SHA256_DIGEST_LENGTH</span><span class="p">))</span>
<span class="k">return</span> <span class="nf">hexdigest</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">hmac</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="kt">NSString</span><span class="p">,</span> <span class="nv">key</span><span class="p">:</span> <span class="kt">NSData</span><span class="p">)</span> <span class="o">-></span> <span class="kt">NSData</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">keyBytes</span> <span class="o">=</span> <span class="kt">UnsafePointer</span><span class="o"><</span><span class="kt">CUnsignedChar</span><span class="o">></span><span class="p">(</span><span class="n">key</span><span class="o">.</span><span class="n">bytes</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="nf">cStringUsingEncoding</span><span class="p">(</span><span class="kt">NSUTF8StringEncoding</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">dataLen</span> <span class="o">=</span> <span class="kt">Int</span><span class="p">(</span><span class="n">string</span><span class="o">.</span><span class="nf">lengthOfBytesUsingEncoding</span><span class="p">(</span><span class="kt">NSUTF8StringEncoding</span><span class="p">))</span>
<span class="k">let</span> <span class="nv">digestLen</span> <span class="o">=</span> <span class="kt">Int</span><span class="p">(</span><span class="kt">CC_SHA256_DIGEST_LENGTH</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">result</span> <span class="o">=</span> <span class="kt">UnsafeMutablePointer</span><span class="o"><</span><span class="kt">CUnsignedChar</span><span class="o">>.</span><span class="nf">alloc</span><span class="p">(</span><span class="n">digestLen</span><span class="p">)</span>
<span class="kt">CCHmac</span><span class="p">(</span><span class="kt">CCHmacAlgorithm</span><span class="p">(</span><span class="n">kCCHmacAlgSHA256</span><span class="p">),</span> <span class="n">keyBytes</span><span class="p">,</span> <span class="n">key</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">dataLen</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="k">return</span> <span class="kt">NSData</span><span class="p">(</span><span class="nv">bytes</span><span class="p">:</span> <span class="n">result</span><span class="p">,</span> <span class="nv">length</span><span class="p">:</span> <span class="n">digestLen</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">hexdigest</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span> <span class="kt">NSData</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">hex</span> <span class="o">=</span> <span class="kt">String</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">bytes</span> <span class="o">=</span> <span class="kt">UnsafePointer</span><span class="o"><</span><span class="kt">CUnsignedChar</span><span class="o">></span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">bytes</span><span class="p">)</span>
<span class="k">for</span> <span class="p">(</span><span class="k">var</span> <span class="nv">i</span><span class="p">:</span> <span class="kt">Int</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o"><</span><span class="n">data</span><span class="o">.</span><span class="n">length</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
<span class="n">hex</span> <span class="o">+=</span> <span class="kt">String</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"%02x"</span><span class="p">,</span> <span class="n">bytes</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">hex</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">timestamp</span><span class="p">(</span><span class="nv">date</span><span class="p">:</span> <span class="kt">NSDate</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">formatter</span> <span class="o">=</span> <span class="kt">NSDateFormatter</span><span class="p">()</span>
<span class="n">formatter</span><span class="o">.</span><span class="n">dateFormat</span> <span class="o">=</span> <span class="s">"yyyyMMdd'T'HHmmss'Z'"</span>
<span class="n">formatter</span><span class="o">.</span><span class="n">timeZone</span> <span class="o">=</span> <span class="kt">NSTimeZone</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"UTC"</span><span class="p">)</span>
<span class="n">formatter</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="kt">NSLocale</span><span class="p">(</span><span class="nv">localeIdentifier</span><span class="p">:</span> <span class="s">"en_US_POSIX"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">formatter</span><span class="o">.</span><span class="nf">stringFromDate</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// MARK: Methods Ported from AWS SDK</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">authorization</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">NSURL</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="kt">Dictionary</span><span class="o"><</span><span class="kt">String</span><span class="p">,</span> <span class="kt">String</span><span class="o">></span><span class="p">,</span> <span class="nv">datetime</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">cred</span> <span class="o">=</span> <span class="nf">credential</span><span class="p">(</span><span class="n">datetime</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">shead</span> <span class="o">=</span> <span class="nf">signedHeaders</span><span class="p">(</span><span class="n">headers</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">sig</span> <span class="o">=</span> <span class="nf">signature</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="n">headers</span><span class="p">,</span> <span class="nv">datetime</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="n">httpMethod</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="n">bodyDigest</span><span class="p">)</span>
<span class="k">return</span> <span class="p">[</span>
<span class="s">"AWS4-HMAC-SHA256 Credential=</span><span class="se">\(</span><span class="n">cred</span><span class="se">)</span><span class="s">"</span><span class="p">,</span>
<span class="s">"SignedHeaders=</span><span class="se">\(</span><span class="n">shead</span><span class="se">)</span><span class="s">"</span><span class="p">,</span>
<span class="s">"Signature=</span><span class="se">\(</span><span class="n">sig</span><span class="se">)</span><span class="s">"</span><span class="p">,</span>
<span class="p">]</span><span class="o">.</span><span class="nf">joinWithSeparator</span><span class="p">(</span><span class="s">", "</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">credential</span><span class="p">(</span><span class="nv">datetime</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">"</span><span class="se">\(</span><span class="n">accessKey</span><span class="se">)</span><span class="s">/</span><span class="se">\(</span><span class="nf">credentialScope</span><span class="p">(</span><span class="n">datetime</span><span class="p">)</span><span class="se">)</span><span class="s">"</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">signedHeaders</span><span class="p">(</span><span class="nv">headers</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span><span class="kt">String</span><span class="p">])</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">list</span> <span class="o">=</span> <span class="kt">Array</span><span class="p">(</span><span class="n">headers</span><span class="o">.</span><span class="n">keys</span><span class="p">)</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="n">lowercaseString</span> <span class="p">}</span><span class="o">.</span><span class="nf">sort</span><span class="p">()</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">itemIndex</span> <span class="o">=</span> <span class="n">list</span><span class="o">.</span><span class="nf">indexOf</span><span class="p">(</span><span class="s">"authorization"</span><span class="p">)</span> <span class="p">{</span>
<span class="n">list</span><span class="o">.</span><span class="nf">removeAtIndex</span><span class="p">(</span><span class="n">itemIndex</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">list</span><span class="o">.</span><span class="nf">joinWithSeparator</span><span class="p">(</span><span class="s">";"</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">canonicalHeaders</span><span class="p">(</span><span class="nv">headers</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">String</span><span class="p">])</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">list</span> <span class="o">=</span> <span class="p">[</span><span class="kt">String</span><span class="p">]()</span>
<span class="k">let</span> <span class="nv">keys</span> <span class="o">=</span> <span class="kt">Array</span><span class="p">(</span><span class="n">headers</span><span class="o">.</span><span class="n">keys</span><span class="p">)</span><span class="o">.</span><span class="n">sort</span> <span class="p">{</span><span class="nv">$0</span><span class="o">.</span><span class="nf">localizedCompare</span><span class="p">(</span><span class="nv">$1</span><span class="p">)</span> <span class="o">==</span> <span class="kt">NSComparisonResult</span><span class="o">.</span><span class="kt">OrderedAscending</span><span class="p">}</span>
<span class="k">for</span> <span class="n">key</span> <span class="k">in</span> <span class="n">keys</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">key</span><span class="o">.</span><span class="nf">caseInsensitiveCompare</span><span class="p">(</span><span class="s">"authorization"</span><span class="p">)</span> <span class="o">!=</span> <span class="kt">NSComparisonResult</span><span class="o">.</span><span class="kt">OrderedSame</span> <span class="p">{</span>
<span class="c1">// Note: This does not strip whitespace, but the spec says it should</span>
<span class="n">list</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="s">"</span><span class="se">\(</span><span class="n">key</span><span class="o">.</span><span class="n">lowercaseString</span><span class="se">)</span><span class="s">:</span><span class="se">\(</span><span class="n">headers</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">!</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">list</span><span class="o">.</span><span class="nf">joinWithSeparator</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">signature</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">NSURL</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">String</span><span class="p">],</span> <span class="nv">datetime</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">secret</span> <span class="o">=</span> <span class="kt">NSString</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"AWS4%@"</span><span class="p">,</span> <span class="n">secretKey</span><span class="p">)</span><span class="o">.</span><span class="nf">dataUsingEncoding</span><span class="p">(</span><span class="kt">NSUTF8StringEncoding</span><span class="p">)</span><span class="o">!</span>
<span class="k">let</span> <span class="nv">date</span> <span class="o">=</span> <span class="nf">hmac</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="nf">substringToIndex</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">startIndex</span><span class="o">.</span><span class="nf">advancedBy</span><span class="p">(</span><span class="mi">8</span><span class="p">)),</span> <span class="nv">key</span><span class="p">:</span> <span class="n">secret</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">region</span> <span class="o">=</span> <span class="nf">hmac</span><span class="p">(</span><span class="n">regionName</span><span class="p">,</span> <span class="nv">key</span><span class="p">:</span> <span class="n">date</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">service</span> <span class="o">=</span> <span class="nf">hmac</span><span class="p">(</span><span class="n">serviceName</span><span class="p">,</span> <span class="nv">key</span><span class="p">:</span> <span class="n">region</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">credentials</span> <span class="o">=</span> <span class="nf">hmac</span><span class="p">(</span><span class="s">"aws4_request"</span><span class="p">,</span> <span class="nv">key</span><span class="p">:</span> <span class="n">service</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">string</span> <span class="o">=</span> <span class="nf">stringToSign</span><span class="p">(</span><span class="n">datetime</span><span class="p">,</span> <span class="nv">url</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="n">headers</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="n">httpMethod</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="n">bodyDigest</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">sig</span> <span class="o">=</span> <span class="nf">hmac</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="nv">key</span><span class="p">:</span> <span class="n">credentials</span><span class="p">)</span>
<span class="k">return</span> <span class="nf">hexdigest</span><span class="p">(</span><span class="n">sig</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">credentialScope</span><span class="p">(</span><span class="nv">datetime</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">[</span>
<span class="n">datetime</span><span class="o">.</span><span class="nf">substringToIndex</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">startIndex</span><span class="o">.</span><span class="nf">advancedBy</span><span class="p">(</span><span class="mi">8</span><span class="p">)),</span>
<span class="n">regionName</span><span class="p">,</span>
<span class="n">serviceName</span><span class="p">,</span>
<span class="s">"aws4_request"</span>
<span class="p">]</span><span class="o">.</span><span class="nf">joinWithSeparator</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">stringToSign</span><span class="p">(</span><span class="nv">datetime</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">url</span><span class="p">:</span> <span class="kt">NSURL</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">String</span><span class="p">],</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">[</span>
<span class="s">"AWS4-HMAC-SHA256"</span><span class="p">,</span>
<span class="n">datetime</span><span class="p">,</span>
<span class="nf">credentialScope</span><span class="p">(</span><span class="n">datetime</span><span class="p">),</span>
<span class="nf">sha256</span><span class="p">(</span><span class="nf">canonicalRequest</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="n">headers</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="n">httpMethod</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="n">bodyDigest</span><span class="p">)),</span>
<span class="p">]</span><span class="o">.</span><span class="nf">joinWithSeparator</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">private</span> <span class="kd">func</span> <span class="nf">canonicalRequest</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">NSURL</span><span class="p">,</span> <span class="nv">headers</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">String</span><span class="p">],</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">[</span>
<span class="n">httpMethod</span><span class="p">,</span> <span class="c1">// HTTP Method</span>
<span class="nf">pathForURL</span><span class="p">(</span><span class="n">url</span><span class="p">),</span> <span class="c1">// Resource Path</span>
<span class="n">url</span><span class="o">.</span><span class="n">query</span> <span class="p">??</span> <span class="s">""</span><span class="p">,</span> <span class="c1">// Canonicalized Query String</span>
<span class="s">"</span><span class="se">\(</span><span class="nf">canonicalHeaders</span><span class="p">(</span><span class="n">headers</span><span class="p">)</span><span class="se">)\n</span><span class="s">"</span><span class="p">,</span> <span class="c1">// Canonicalized Header String (Plus a newline for some reason)</span>
<span class="nf">signedHeaders</span><span class="p">(</span><span class="n">headers</span><span class="p">),</span> <span class="c1">// Signed Headers String</span>
<span class="n">bodyDigest</span><span class="p">,</span> <span class="c1">// Sha265 of Body</span>
<span class="p">]</span><span class="o">.</span><span class="nf">joinWithSeparator</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To use this code:</p>
<ul>
<li>You will need a file to upload, and a SHA256 Hash of that file</li>
<li>Create a <code class="highlighter-rouge">S3V4Signer</code> with your AWS creds and the file info</li>
<li>Copy all the headers returned into your request object</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">path</span> <span class="o">=</span> <span class="s">"path/to/file.png"</span>
<span class="k">let</span> <span class="nv">bodyDigest</span> <span class="o">=</span> <span class="kt">FileHash</span><span class="o">.</span><span class="nf">sha256HashOfFileAtPath</span><span class="p">(</span><span class="n">path</span><span class="p">)</span><span class="o">!</span>
<span class="k">let</span> <span class="nv">url</span> <span class="o">=</span> <span class="kt">NSURL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"https://capturedeu.s3-eu-central-1.amazonaws.com/remote-file-name"</span><span class="p">)</span><span class="o">!</span>
<span class="k">let</span> <span class="nv">request</span> <span class="o">=</span> <span class="kt">NSMutableURLRequest</span><span class="p">(</span><span class="kt">URL</span><span class="p">:</span> <span class="n">url</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">fileStream</span> <span class="o">=</span> <span class="kt">NSInputStream</span><span class="p">(</span><span class="nv">fileAtPath</span><span class="p">:</span> <span class="n">path</span><span class="p">)</span><span class="o">!</span>
<span class="n">request</span><span class="o">.</span><span class="kt">HTTPMethod</span> <span class="o">=</span> <span class="s">"PUT"</span>
<span class="n">request</span><span class="o">.</span><span class="kt">HTTPBodyStream</span> <span class="o">=</span> <span class="n">fileStream</span>
<span class="k">let</span> <span class="nv">signer</span> <span class="o">=</span> <span class="kt">S3V4Signer</span><span class="p">(</span><span class="nv">accessKey</span><span class="p">:</span> <span class="n">accessKey</span><span class="o">!</span><span class="p">,</span> <span class="nv">secretKey</span><span class="p">:</span> <span class="n">secretKey</span><span class="o">!</span><span class="p">,</span> <span class="nv">regionName</span><span class="p">:</span> <span class="n">regionName</span><span class="o">!</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">headers</span> <span class="o">=</span> <span class="n">signer</span><span class="o">.</span><span class="nf">signedHeaders</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="n">bodyDigest</span><span class="p">)</span>
<span class="k">for</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span> <span class="k">in</span> <span class="n">headers</span> <span class="p">{</span>
<span class="n">request</span><span class="o">.</span><span class="nf">addValue</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nv">forHTTPHeaderField</span><span class="p">:</span> <span class="n">key</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">request</span><span class="o">.</span><span class="nf">addValue</span><span class="p">(</span><span class="nf">sizeForPath</span><span class="p">(</span><span class="n">path</span><span class="p">),</span> <span class="nv">forHTTPHeaderField</span><span class="p">:</span> <span class="s">"Content-Length"</span><span class="p">)</span>
<span class="n">request</span><span class="o">.</span><span class="nf">addValue</span><span class="p">(</span><span class="s">"image/png"</span><span class="p">,</span> <span class="nv">forHTTPHeaderField</span><span class="p">:</span> <span class="s">"Content-Type"</span><span class="p">)</span>
<span class="k">var</span> <span class="nv">response</span><span class="p">:</span> <span class="kt">NSURLResponse</span><span class="p">?</span>
<span class="k">do</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="k">try</span> <span class="kt">NSURLConnection</span><span class="o">.</span><span class="nf">sendSynchronousRequest</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="nv">returningResponse</span><span class="p">:</span> <span class="o">&</span><span class="n">response</span><span class="p">)</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">httpResponse</span> <span class="o">=</span> <span class="n">response</span> <span class="k">as?</span> <span class="kt">NSHTTPURLResponse</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">text</span> <span class="o">=</span> <span class="kt">NSString</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span><span class="n">data</span><span class="p">,</span> <span class="nv">encoding</span><span class="p">:</span><span class="kt">NSUTF8StringEncoding</span><span class="p">)</span> <span class="k">as?</span> <span class="kt">String</span>
<span class="kt">NSLog</span><span class="p">(</span><span class="s">"Response from AWS S3: </span><span class="se">\(</span><span class="n">httpResponse</span><span class="o">.</span><span class="n">description</span><span class="se">)\n\(</span><span class="n">text</span><span class="o">!</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span> <span class="nf">catch</span> <span class="p">(</span><span class="k">let</span> <span class="nv">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">print</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The final integration test for this class. I was able to TDD my way through the while porting things, but wanted to make most of the methods private so wound up deleting many of the intermediate tests. I am confident this will catch any breaking changes for my use.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">XCTest</span>
<span class="kd">class</span> <span class="kt">S3V4SignerTests</span><span class="p">:</span> <span class="kt">XCTestCase</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">accessKey</span> <span class="o">=</span> <span class="s">"AKIAJODU6PESZF6ENZ2A"</span>
<span class="k">let</span> <span class="nv">secretKey</span> <span class="o">=</span> <span class="s">"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"</span> <span class="c1">// This key has been deleted, BTW</span>
<span class="k">let</span> <span class="nv">regionName</span> <span class="o">=</span> <span class="s">"eu-central-1"</span>
<span class="k">let</span> <span class="nv">bodyDigest</span> <span class="o">=</span> <span class="s">"96fe862bffd24748621f5e6b1938c3f7a8a18569c82b68dccad1e22b20533440"</span>
<span class="kd">func</span> <span class="nf">testAuthorizationHeader</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">now</span> <span class="o">=</span> <span class="nf">parseDate</span><span class="p">(</span><span class="s">"20160318T003250Z"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">url</span> <span class="o">=</span> <span class="kt">NSURL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"https://capturedeu.s3-eu-central-1.amazonaws.com/xrQ77e9S"</span><span class="p">)</span><span class="o">!</span>
<span class="k">let</span> <span class="nv">signer</span> <span class="o">=</span> <span class="kt">S3V4Signer</span><span class="p">(</span><span class="nv">accessKey</span><span class="p">:</span> <span class="n">accessKey</span><span class="p">,</span> <span class="nv">secretKey</span><span class="p">:</span> <span class="n">secretKey</span><span class="p">,</span> <span class="nv">regionName</span><span class="p">:</span> <span class="n">regionName</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">headers</span> <span class="o">=</span> <span class="n">signer</span><span class="o">.</span><span class="nf">signedHeaders</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="nv">bodyDigest</span><span class="p">:</span> <span class="n">bodyDigest</span><span class="p">,</span> <span class="nv">httpMethod</span><span class="p">:</span> <span class="s">"PUT"</span><span class="p">,</span> <span class="nv">date</span><span class="p">:</span> <span class="n">now</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">expected</span> <span class="o">=</span> <span class="s">"AWS4-HMAC-SHA256 Credential=AKIAJODU6PESZF6ENZ2A/20160318/eu-central-1/s3/aws4_request, SignedHeaders=host;x-amz-acl;x-amz-content-sha256;x-amz-date, Signature=1d83730c0ad27d6b50864f770a6cac8467053d14fb7381cf6f123b2d21f1ae03"</span>
<span class="kt">XCTAssert</span><span class="p">(</span><span class="n">expected</span> <span class="o">==</span> <span class="n">headers</span><span class="p">[</span><span class="s">"Authorization"</span><span class="p">])</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">parseDate</span><span class="p">(</span><span class="nv">date</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">NSDate</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">formatter</span> <span class="o">=</span> <span class="kt">NSDateFormatter</span><span class="p">()</span>
<span class="n">formatter</span><span class="o">.</span><span class="n">dateFormat</span> <span class="o">=</span> <span class="s">"yyyyMMdd'T'HHmmss'Z'"</span>
<span class="n">formatter</span><span class="o">.</span><span class="n">timeZone</span> <span class="o">=</span> <span class="kt">NSTimeZone</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"UTC"</span><span class="p">)</span>
<span class="n">formatter</span><span class="o">.</span><span class="n">locale</span> <span class="o">=</span> <span class="kt">NSLocale</span><span class="p">(</span><span class="nv">localeIdentifier</span><span class="p">:</span> <span class="s">"en_US_POSIX"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">formatter</span><span class="o">.</span><span class="nf">dateFromString</span><span class="p">(</span><span class="n">date</span><span class="p">)</span><span class="o">!</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I would love to hear if you found this helpful.</p>
<p>All code in this post covered by the <a href="https://en.wikipedia.org/wiki/MIT_License">Apache 2.0 License</a>, as was the <a href="https://github.com/aws/aws-sdk-ios/blob/master/LICENSE">code from which</a> it was ported.</p>
Simple NSData hexdigest utility in swift2016-03-18T00:00:00+00:00http://www.codeography.com/2016/03/18/simple-nsdata-hexdigest-utility-in-swift<p>I needed an easy way to convert <code class="highlighter-rouge">NSData</code> to a hexdigest in swift. Since I am working on library code addin extensions to core classes would be bad form, so what I needed was a simple utility I could drop into a class.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">func</span> <span class="nf">hexdigest</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span> <span class="kt">NSData</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">hex</span> <span class="o">=</span> <span class="kt">String</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">bytes</span> <span class="o">=</span> <span class="kt">UnsafePointer</span><span class="o"><</span><span class="kt">CUnsignedChar</span><span class="o">></span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">bytes</span><span class="p">)</span>
<span class="k">for</span> <span class="p">(</span><span class="k">var</span> <span class="nv">i</span><span class="p">:</span> <span class="kt">Int</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o"><</span><span class="n">data</span><span class="o">.</span><span class="n">length</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
<span class="n">hex</span> <span class="o">+=</span> <span class="kt">String</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"%02x"</span><span class="p">,</span> <span class="n">bytes</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">hex</span>
<span class="p">}</span>
</code></pre></div></div>
Calling CCHmac from swift2016-03-18T00:00:00+00:00http://www.codeography.com/2016/03/18/calling-cchmac-from-swift<p>I wanted to keep things minimal. Avoid the added complexity of creating a generic class that could handle all the different digest types and instead just have a small method I could drop into a class if needed. I also prefer to avoid adding categories to core classes, so adding an extension to <code class="highlighter-rouge">NSString</code> wasn’t really what I wanted.</p>
<p>Add the following include to your <code class="highlighter-rouge">-Bridging-Header.h</code> file:</p>
<pre><code class="language-objective-c">#import <CommonCrypto/CommonHMAC.h>
</code></pre>
<p>Then in the class that needs to call CCHmac() add a private method:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">func</span> <span class="nf">hmac</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="kt">NSString</span><span class="p">,</span> <span class="nv">key</span><span class="p">:</span> <span class="kt">NSData</span><span class="p">)</span> <span class="o">-></span> <span class="kt">NSData</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">keyBytes</span> <span class="o">=</span> <span class="kt">UnsafePointer</span><span class="o"><</span><span class="kt">CUnsignedChar</span><span class="o">></span><span class="p">(</span><span class="n">key</span><span class="o">.</span><span class="n">bytes</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="nf">cStringUsingEncoding</span><span class="p">(</span><span class="kt">NSUTF8StringEncoding</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">dataLen</span> <span class="o">=</span> <span class="kt">Int</span><span class="p">(</span><span class="n">string</span><span class="o">.</span><span class="nf">lengthOfBytesUsingEncoding</span><span class="p">(</span><span class="kt">NSUTF8StringEncoding</span><span class="p">))</span>
<span class="k">let</span> <span class="nv">digestLen</span> <span class="o">=</span> <span class="kt">Int</span><span class="p">(</span><span class="kt">CC_SHA256_DIGEST_LENGTH</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">result</span> <span class="o">=</span> <span class="kt">UnsafeMutablePointer</span><span class="o"><</span><span class="kt">CUnsignedChar</span><span class="o">>.</span><span class="nf">alloc</span><span class="p">(</span><span class="n">digestLen</span><span class="p">)</span>
<span class="kt">CCHmac</span><span class="p">(</span><span class="kt">CCHmacAlgorithm</span><span class="p">(</span><span class="n">kCCHmacAlgSHA256</span><span class="p">),</span> <span class="n">keyBytes</span><span class="p">,</span> <span class="n">key</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">dataLen</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="k">return</span> <span class="kt">NSData</span><span class="p">(</span><span class="nv">bytes</span><span class="p">:</span> <span class="n">result</span><span class="p">,</span> <span class="nv">length</span><span class="p">:</span> <span class="n">digestLen</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If I need a different <code class="highlighter-rouge">CCHmacAlgorithm</code> I would just replace the two constants in that method with the appropriate ones.</p>
AWS Version 4 Signing Key on Mac2016-02-19T00:00:00+00:00http://www.codeography.com/2016/02/19/aws-version-4-signing-key-on-mac<p>Or <strong>How to Derive a Version 4 Signing Key for a Mac App</strong></p>
<p>I have been working on a major update to <a href="http://www.capturedapp.com/">Captured</a>, and heard back from one of the beta testers that uses S3 in the <code class="highlighter-rouge">eu-central-1</code> region. Turns out that is one of the newer regions that requires the <code class="highlighter-rouge">AWS4-HMAC-SHA256</code> Authorization Method. After a bit of research I found Amazon’s <a href="http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html">Signature Version 4 Signing Process</a> which describes how to do the signing. They even provide a <a href="http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-other">few code examples</a>, however they didn’t have any that used Swift or Objective-C.</p>
<p>I really wanted to use swift, since the vast majority of Captured is written in swift, but I quicly discovered the pain that is C-interop. So I wrote an Objective-C class that will deal with that. And after a simple line in my bridging header it was very easy to use in swift.</p>
<p>If you want to do this in Objective-C, here’s the tl;dr:</p>
<h2 id="deriving-the-signing-key-with-objective-c">Deriving the Signing Key with Objective C</h2>
<pre><code class="language-objective-c">+ (NSData *)hmacSha256ForString:(NSString *)stringToSign withKey:(NSData *)key {
NSData *dataToSign = [stringToSign dataUsingEncoding:NSUTF8StringEncoding];
unsigned char rawDigest[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, [key bytes], [key length], [dataToSign bytes], [dataToSign length], rawDigest);
return [[NSData alloc] initWithBytes:rawDigest length:CC_SHA256_DIGEST_LENGTH];
}
+ (NSData *)getSignatureKey:(NSString *)key dateStamp:(NSString *)dateStamp regionName:(NSString *)regionName serviceName:(NSString *)serviceName {
NSData *kSecret = [[NSString stringWithFormat:@"AWS4%@", key] dataUsingEncoding:NSUTF8StringEncoding];
NSData *kDate = [self hmacSha256ForString: dateStamp withKey:kSecret];
NSData *kRegion = [self hmacSha256ForString: regionName withKey:kDate];
NSData *kService = [self hmacSha256ForString: serviceName withKey:kRegion];
NSData *kSigning = [self hmacSha256ForString: @"aws4_request" withKey:kService];
return kSigning;
}
</code></pre>
<h2 id="few-more-details">Few more details:</h2>
<p>I added a few <code class="highlighter-rouge">NSLog</code> statements to test thigns along the way. This turned out to be very importatn, because I had a few bugs (mostly around buffer lengths) that would make things look like they were working. The first few steps matched the reference output, but not all of them. I needed all of the steps to work. Here is my test code that I ran to get things working:</p>
<pre><code class="language-objective-c">#import <CommonCrypto/CommonHMAC.h>
#import "AWS4SigningKey.h"
@implementation AWS4SigningKey
+ (NSData *)hmacSha256ForString:(NSString *)stringToSign withKey:(NSData *)key {
NSData *dataToSign = [stringToSign dataUsingEncoding:NSUTF8StringEncoding];
unsigned char rawDigest[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, [key bytes], [key length], [dataToSign bytes], [dataToSign length], rawDigest);
return [[NSData alloc] initWithBytes:rawDigest length:CC_SHA256_DIGEST_LENGTH];
}
+ (NSData *)getSignatureKey:(NSString *)key
dateStamp:(NSString *)dateStamp
regionName:(NSString *)regionName
serviceName:(NSString *)serviceName {
NSData *kSecret = [[NSString stringWithFormat:@"AWS4%@", key] dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@", [kSecret description]);
NSData *kDate = [self hmacSha256ForString: dateStamp withKey:kSecret];
NSLog(@"%@", [kDate description]);
NSData *kRegion = [self hmacSha256ForString: regionName withKey:kDate];
NSLog(@"%@", [kRegion description]);
NSData *kService = [self hmacSha256ForString: serviceName withKey:kRegion];
NSLog(@"%@", [kService description]);
NSData *kSigning = [self hmacSha256ForString: @"aws4_request" withKey:kService];
NSLog(@"%@", [kSigning description]);
return kSigning;
}
@end
</code></pre>
<p>Then when I run this bit of Swift code:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">key</span> <span class="o">=</span> <span class="s">"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"</span>
<span class="k">let</span> <span class="nv">dateStamp</span> <span class="o">=</span> <span class="s">"20120215"</span>
<span class="k">let</span> <span class="nv">regionName</span> <span class="o">=</span> <span class="s">"us-east-1"</span>
<span class="k">let</span> <span class="nv">serviceName</span> <span class="o">=</span> <span class="s">"iam"</span>
<span class="kt">AWS4SigningKey</span><span class="o">.</span><span class="nf">getSignatureKey</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nv">dateStamp</span><span class="p">:</span> <span class="n">dateStamp</span><span class="p">,</span> <span class="nv">regionName</span><span class="p">:</span> <span class="n">regionName</span><span class="p">,</span> <span class="nv">serviceName</span><span class="p">:</span> <span class="n">serviceName</span><span class="p">)</span>
</code></pre></div></div>
<p>This output:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2016-02-19 23:00:34.493 Captured[29081:3568690] <41575334 774a616c 72585574 6e46454d 492f4b37 4d44454e 472b6250 78526669 43594558 414d504c 454b4559>
2016-02-19 23:00:34.493 Captured[29081:3568690] <969fbb94 feb542b7 1ede6f87 fe4d5fa2 9c789342 b0f40747 4670f0c2 489e0a0d>
2016-02-19 23:00:34.493 Captured[29081:3568690] <69daa020 9cd9c5ff 5c8ced46 4a696fd4 252e9814 30b10e3d 3fd8e2f1 97d7a70c>
2016-02-19 23:00:34.493 Captured[29081:3568690] <f72cfd46 f26bc464 3f06a11e abb6c0ba 18780c19 a8da0c31 ace67126 5e3c87fa>
2016-02-19 23:00:34.493 Captured[29081:3568690] <f4780e2d 9f65fa89 5f9c67b3 2ce1baf0 b0d8a435 05a000a1 a9e090d4 14db404d>
</code></pre></div></div>
<p>Which if you delete a few extra spaces, you’ll notice matches the reference from the AWS documentation:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">kSecret</span> <span class="o">=</span> <span class="s1">'41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559'</span>
<span class="n">kDate</span> <span class="o">=</span> <span class="s1">'969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d'</span>
<span class="n">kRegion</span> <span class="o">=</span> <span class="s1">'69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c'</span>
<span class="n">kService</span> <span class="o">=</span> <span class="s1">'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa'</span>
<span class="n">kSigning</span> <span class="o">=</span> <span class="s1">'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d'</span>
</code></pre></div></div>
<p>High-fives all around!</p>
<p>I’d prefer a pure-Swift solution, but this bit of objective-c and the fact that I can omit all the hacky-marshaling to C functions makes me pretty happy. You can find the full class definition <a href="https://gist.github.com/csexton/c2963dd1af4cf4e1dfdb">here</a>.</p>
Export Heroku Postgres to CSV2016-02-11T00:00:00+00:00http://www.codeography.com/2016/02/11/export-heroku-postgres-to-csv<p>I needed to export a table in a Heroku Postgres table. But the <code class="highlighter-rouge">COPY</code> query requires administrator privileges, and I don’t have those on heroku. Luckily you can use the <code class="highlighter-rouge">\COPY</code> command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% heroku pg:psql --app my-app-production
---> Connecting to DATABASE_URL
my-app-production::DATABASE=> select count(*) from some_table;
count
-------
20910
(1 row)
my-app-production::DATABASE=> \copy (SELECT * FROM some_table) TO some_table.csv CSV DELIMITER ','
COPY 20910
</code></pre></div></div>
<p>This writes the contents of <code class="highlighter-rouge">some_table</code> to <code class="highlighter-rouge">some_table.csv</code> in your working directory.</p>
Fix Xcode's Open Quickly Navigation2015-11-27T00:00:00+00:00http://www.codeography.com/2015/11/27/fix_xcodes_open_quickly<p>Open quickly is one of the best features in Xcode. It saves you haveing to move your hand to the mouse and select a different file. But there is no way to navigate through the selection unless you use the arrow keys. The arrow keys that are so, so far from the home row. It baffels me that <code class="highlighter-rouge">Control-N</code> and <code class="highlighter-rouge">Control-P</code>, which are normal Cocoa controls for next and previous (try this in Safari for example).</p>
<p>I knew <a href="https://pqrs.org/osx/karabiner/index.html.en">Karabiner</a> should be able to fix this. It took a little tinkering, but I got it. It is so nice. Also added <code class="highlighter-rouge">Control-J</code> and <code class="highlighter-rouge">Control-K</code> to appease my vim habbits.</p>
<p>Add the following XML to <code class="highlighter-rouge">~/Library/Application\ Support/Karabiner/private.xml</code>, then search for “Xcode” and enable them in Karabiner:</p>
<p><img src="/images/karabiner-xcode.png" alt="karabiner" /></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0"?></span>
<span class="nt"><root></span>
<span class="nt"><appdef></span>
<span class="nt"><appname></span>XCODE<span class="nt"></appname></span>
<span class="nt"><equal></span>com.apple.dt.Xcode<span class="nt"></equal></span>
<span class="nt"></appdef></span>
<span class="nt"><item></span>
<span class="nt"><name></span>Remap Control+N to Down in Xcode<span class="nt"></name></span>
<span class="nt"><appendix></span>Active in Xcode<span class="nt"></appendix></span>
<span class="nt"><identifier></span>private.xcodeNDown<span class="nt"></identifier></span>
<span class="nt"><only></span>XCODE<span class="nt"></only></span>
<span class="nt"><autogen></span>
__KeyToKey__
KeyCode::N, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_CONTROL,
KeyCode::CURSOR_DOWN
<span class="nt"></autogen></span>
<span class="nt"></item></span>
<span class="nt"><item></span>
<span class="nt"><name></span>Remap Control+P to Up in Xcode<span class="nt"></name></span>
<span class="nt"><appendix></span>Active in Xcode<span class="nt"></appendix></span>
<span class="nt"><identifier></span>private.xcodePUp<span class="nt"></identifier></span>
<span class="nt"><only></span>XCODE<span class="nt"></only></span>
<span class="nt"><autogen></span>
__KeyToKey__
KeyCode::P, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_CONTROL,
KeyCode::CURSOR_UP
<span class="nt"></autogen></span>
<span class="nt"></item></span>
<span class="nt"><item></span>
<span class="nt"><name></span>Remap Control+J to Down in Xcode<span class="nt"></name></span>
<span class="nt"><appendix></span>Active in Xcode<span class="nt"></appendix></span>
<span class="nt"><identifier></span>private.xcodeJDown<span class="nt"></identifier></span>
<span class="nt"><only></span>XCODE<span class="nt"></only></span>
<span class="nt"><autogen></span>
__KeyToKey__
KeyCode::J, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_CONTROL,
KeyCode::CURSOR_DOWN
<span class="nt"></autogen></span>
<span class="nt"></item></span>
<span class="nt"><item></span>
<span class="nt"><name></span>Remap Control+K to Up in Xcode<span class="nt"></name></span>
<span class="nt"><appendix></span>Active in Xcode<span class="nt"></appendix></span>
<span class="nt"><identifier></span>private.xcodeKUp<span class="nt"></identifier></span>
<span class="nt"><only></span>XCODE<span class="nt"></only></span>
<span class="nt"><autogen></span>
__KeyToKey__
KeyCode::K, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_CONTROL,
KeyCode::CURSOR_UP
<span class="nt"></autogen></span>
<span class="nt"></item></span>
<span class="nt"></root></span>
</code></pre></div></div>
<p>You can find all my Karabiner settings in my <a href="https://github.com/csexton/dotfiles/tree/master/karabiner">dotfiles repo</a> on GitHub.</p>
Testing for TLS 1.22015-09-21T00:00:00+00:00http://www.codeography.com/2015/09/21/testing_for_tls_12<p>iOS 9 requires all <code class="highlighter-rouge">NSURLConnection</code> connections to <a href="https://developer.apple.com/library/ios/technotes/tn2287/_index.html">support TLS 1.2</a>. So I needed to check my servers to see if this was indeed configured. After looking around a bit I was able to find that you could test for this using <code class="highlighter-rouge">openssl</code>.</p>
<p>On OS X with homebrew you can test with this command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/local/Cellar/openssl/1.0.2d_1/bin/openssl s_client -tls1_2 -connect www.codeography.com:443
</code></pre></div></div>
<p>If you have linux (with a new enough <code class="highlighter-rouge">openssl</code>) or have overridden the system <code class="highlighter-rouge">openssl</code> on OS X you can just leave off the full path:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -tls1_2 -connect www.codeography.com:443
</code></pre></div></div>
<p>If it is supported you’ll see the Certificate chain as well as some information about the connection. The bit I was looking for was “Protocol: TLSv1.2”</p>
<p>Looked something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
SSL-Session:
Protocol : TLSv1.2
TLS session ticket lifetime hint: 1200 (seconds)
</code></pre></div></div>
Playing Minecraft when the Port is Blocked2015-08-02T00:00:00+00:00http://www.codeography.com/2015/08/02/playing_minecraft_when_the_port_is_blocked<p>I was at a conference this last weekend and the network blocked the port that minecraft needed to connect to the server. So I spent longer than I would like to admit setting up a ssh tunnel. Here’s what I did:</p>
<h3 id="1-create-the-tunnel">1) Create the tunnel</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 8080:yourminecraftserver.club:25565 -p 22 -l yoursshuser -N yoursshserver.com
</code></pre></div></div>
<p>This will stay running in the terminal. Just leave it going while you play.</p>
<h3 id="2-configure-minecraft-to-use-that-tunnel">2) Configure minecraft to use that tunnel</h3>
<p>Create a new server by selecting “Multiplayer -> Add Server” and use the following settings:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Server Name:
Proxy
Server Address:
localhost:8080
</code></pre></div></div>
<p>Now you should be able to connect and build that dirt hobble you’ve been planning.</p>
How do you write great commit messages?2015-02-17T00:00:00+00:00http://www.codeography.com/2015/02/17/great_commit_message<p>The best way to learn to write great commit messages is to go back and read them.</p>
<p>When reading code take a moment and go look at the git history every time you mutter “why did they do that.” That’s the point in time when you want to know the real “why” behind the change. If you don’t already know how to to that, take moment to figure out a way quickly to access the history of a line in <a href="https://magit.github.io/">your</a> <a href="https://github.com/tpope/vim-fugitive">editor</a> or in <a href="https://github.com/blog/228-playing-the-blame-game">your</a> <a href="http://git-scm.com/docs/git-blame">repo</a>, the less friction the easier it is to go back and read about the changes.</p>
<p>If you make a habit out of this, you will quickly learn what is helpful and what is not. Then, if you are like me, you’ll want to go back to slap your past-self for being lazy and giving a few bullet points of “what” was changed and not “why” it was changed.</p>
<p>Sound good? You in? Cool.</p>
<p>To get started just add the word “<a href="https://twitter.com/sarahmei/status/566667320425066497">because</a>” to your commits.</p>
<p>Lets look at an example.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Changed the post title font size
Changed 0.8em 16px.
h2 {
<span class="gd">- font-size: 0.8em;
</span><span class="gi">+ font-size: 16px;
</span>}
</code></pre></div></div>
<p>And what if I ever come across this file, I might wonder why this person strayed from the convention of using relative font sizes to pixels. I would would mutter “wtf” to myself and pop open the <code class="highlighter-rouge">git blame</code> in my editor for that line and read the commit message. This right here is the point that I want to know why.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Changed the post title font size
Fixed it to 16 pixels because when we increased the overall font size on
the blog the titles were wrapping on mobile views.
h2 {
<span class="gd">- font-size: 0.8em;
</span><span class="gi">+ font-size: 16px;
</span>}
</code></pre></div></div>
<p>Now this is helpful. It gives me context. I get clues on what changed in this code and what might break. And I can see that it wasn’t some arbitrary change. Me in 6 months will appreciate this.</p>
<p>A commit already contains a <code class="highlighter-rouge">diff</code>, so it shows what was changed. No reason to write that up again. But nothing explains why you made that horrible hack or sweeping change.</p>
<p>Communicating the current reasoning to your future self is a super power.</p>
<hr />
<h3 id="further-reading">Further Reading</h3>
<p>There have been many posts about commit message from formatting to content. Here are a few of my favorite, should you want to level up:</p>
<p>Tim Pope’s <a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">A Note About Git Commit Messages</a>. This is formatting and syntax, but if you follow this I will be much, much happier.</p>
<p>Caleb Thompson’s <a href="http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message">5 Useful Tips For A Better Commit Message</a>. A bit vim-centric, but great guidelines.</p>
<p>Stephen Ball’s <a href="http://rakeroutes.com/blog/deliberate-git/">Deliberate Git</a>. An in depth guide to commit messages. Worth the time to read and understand.</p>
<p>Keavy McMinn’s <a href="https://github.com/blog/1943-how-to-write-the-perfect-pull-request">How to write the perfect pull request</a>. Slightly different than commit messages, but they really go well together.</p>
Render a JBuilder template outside of a request2015-02-05T00:00:00+00:00http://www.codeography.com/2015/02/05/render-jbuilder-template<p>I like to use the built-in JBuilder for rendering JSON in my Rails apps. I particularly like that it is an actual view template, gives you the control and tools you need to easily build up the document. There is no need to teach your models about icky things like URLs and hostnames – that can be rendered with view helpers as part of the request.</p>
<p>The one problem is there is no easy way to use those templates outside of a Rails response. But luckily <a href="https://github.com/cupakromer">Aaron</a> came up with a helpful class to setup everything properly and mimic the <code class="highlighter-rouge">Request</code>. He even added support for setting things like the <code class="highlighter-rouge">location</code> header.</p>
<p>To use it in a service object (like say a rake task that runs on a worker process):</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Create the object</span>
<span class="n">json_view</span> <span class="o">=</span> <span class="no">JsonView</span><span class="p">.</span><span class="nf">new</span>
<span class="c1"># Set any headers that matter, where `posts` is the obligatory example resource.</span>
<span class="n">location</span> <span class="o">=</span> <span class="n">json_view</span><span class="p">.</span><span class="nf">location_url</span><span class="p">(</span><span class="n">posts</span><span class="p">)</span>
<span class="c1"># Render the template</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">json_view</span><span class="p">.</span><span class="nf">render</span><span class="p">(</span><span class="ss">:show</span><span class="p">,</span> <span class="ss">posts: </span><span class="n">posts</span><span class="p">)</span>
</code></pre></div></div>
<p>Pretty cool, eh?</p>
<p>His implmentation that takes care of all the details of the request:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">JsonView</span>
<span class="nb">attr_reader</span> <span class="ss">:controller</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">env</span> <span class="o">=</span> <span class="p">{})</span>
<span class="vi">@controller</span> <span class="o">=</span> <span class="no">API</span><span class="o">::</span><span class="no">V1</span><span class="o">::</span><span class="no">BeaconsController</span><span class="p">.</span><span class="nf">new</span>
<span class="n">controller</span><span class="p">.</span><span class="nf">request</span> <span class="o">=</span> <span class="no">ActionDispatch</span><span class="o">::</span><span class="no">Request</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">default_env</span><span class="p">.</span><span class="nf">merge</span><span class="p">(</span><span class="n">env</span><span class="p">))</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="n">view</span><span class="p">,</span> <span class="o">**</span><span class="n">locals</span><span class="p">)</span>
<span class="n">controller</span><span class="p">.</span><span class="nf">render_to_string</span><span class="p">(</span><span class="n">view</span><span class="p">,</span> <span class="ss">locals: </span><span class="n">locals</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">https?</span>
<span class="vi">@_https</span> <span class="o">||=</span> <span class="no">ENV</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="s2">"SERVER_HTTPS"</span><span class="p">)</span> <span class="p">{</span>
<span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">config</span><span class="p">.</span><span class="nf">force_ssl</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">default_env</span>
<span class="p">{</span>
<span class="s2">"SERVER_NAME"</span> <span class="o">=></span> <span class="no">ENV</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="s2">"SERVER_NAME"</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">abort</span> <span class="s2">"Missing environment key: SERVER_NAME"</span>
<span class="p">},</span>
<span class="s2">"SERVER_PORT"</span> <span class="o">=></span> <span class="n">https?</span> <span class="p">?</span> <span class="s2">"443"</span> <span class="p">:</span> <span class="s2">"80"</span><span class="p">,</span>
<span class="s2">"HTTPS"</span> <span class="o">=></span> <span class="n">https?</span> <span class="p">?</span> <span class="s2">"on"</span> <span class="p">:</span> <span class="s2">"off"</span><span class="p">,</span>
<span class="s2">"rack.url_scheme"</span> <span class="o">=></span> <span class="n">https?</span> <span class="p">?</span> <span class="s2">"https"</span> <span class="p">:</span> <span class="s2">"http"</span><span class="p">,</span>
<span class="s2">"CONTENT_TYPE"</span> <span class="o">=></span> <span class="s2">"application/json"</span><span class="p">,</span>
<span class="s2">"HTTP_ACCEPT"</span> <span class="o">=></span> <span class="s2">"application/json"</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="c1"># Helpful shim reaching into the controller private stuff</span>
<span class="k">def</span> <span class="nf">location_url</span><span class="p">(</span><span class="n">beacons</span><span class="p">)</span>
<span class="n">controller</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:location_url</span><span class="p">,</span> <span class="n">beacons</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">respond_to_missing?</span><span class="p">(</span><span class="n">meth</span><span class="p">,</span> <span class="n">include_all</span><span class="p">)</span>
<span class="n">controller</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="n">meth</span><span class="p">)</span> <span class="o">||</span> <span class="k">super</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="n">sym</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">if</span> <span class="n">controller</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="n">sym</span><span class="p">)</span>
<span class="n">controller</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">sym</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">else</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
Upload to imgur from applescript2014-04-04T00:00:00+00:00http://www.codeography.com/2014/04/04/upload-to-imgur-from-applescript<p>A little scrip</p>
<div class="language-applescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">on</span> <span class="nb">run</span><span class="w"> </span><span class="p">{</span><span class="nv">input</span><span class="p">,</span><span class="w"> </span><span class="nv">parameters</span><span class="p">}</span><span class="w">
</span><span class="k">tell</span><span class="w"> </span><span class="nb">application</span><span class="w"> </span><span class="s2">"Finder"</span><span class="w">
</span><span class="c1">-- convert file paths to posix</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">imageList</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">linkList</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span><span class="k">repeat</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="nv">i</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="nv">input</span><span class="p">)</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nv">imageList</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">POSIX</span><span class="w"> </span><span class="na">path</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="p">(</span><span class="nb">item</span><span class="w"> </span><span class="nv">i</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nv">input</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nv">alias</span><span class="p">)</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">file_name</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="na">name</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="p">(</span><span class="nb">item</span><span class="w"> </span><span class="nv">i</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nv">input</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nv">alias</span><span class="p">)</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="k">repeat</span><span class="w">
</span><span class="c1">-- no images selected</span><span class="w">
</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="nv">imageList</span><span class="p">)</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="k">then</span><span class="w">
</span><span class="nb">display dialog</span><span class="w"> </span><span class="s2">"No image files selected"</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="na">title</span><span class="w"> </span><span class="s2">"Imgur uploader"</span><span class="w"> </span><span class="nb">buttons</span><span class="w"> </span><span class="p">{</span><span class="s2">"Quit"</span><span class="p">}</span><span class="w"> </span><span class="nv">default</span><span class="w"> </span><span class="nb">button</span><span class="w"> </span><span class="s2">"Quit"</span><span class="w">
</span><span class="k">return</span><span class="w">
</span><span class="c1">--upload</span><span class="w">
</span><span class="k">else</span><span class="w">
</span><span class="nb">display</span><span class="w"> </span><span class="nv">notification</span><span class="w"> </span><span class="s2">"Preparing to upload "</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="nv">imageList</span><span class="p">)</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="s2">" images"</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="na">title</span><span class="w"> </span><span class="s2">"Uploaded Started"</span><span class="w">
</span><span class="k">repeat</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="nv">i</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="nv">imageList</span><span class="p">)</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">apiKey</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="s2">"26ff5c40cbedf50e7f81124ab473c1cc"</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">curlCommand</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="s2">"curl -F \"key="</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="nv">apiKey</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="s2">"\" -F \"image=@"</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">i</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nv">imageList</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="s2">"\" http://api.imgur.com/2/upload"</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">answer</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nb">do shell script</span><span class="w"> </span><span class="nv">curlCommand</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">atid</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">AppleScript</span>'s <span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">delimiters</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">AppleScript</span>'s <span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">delimiters</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="s2">"<original>"</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">link</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nv">answer</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">AppleScript</span>'s <span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">delimiters</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="s2">"<"</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">link</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nv">link</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">AppleScript</span>'s <span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">delimiters</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">atid</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="k">end</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nv">linkList</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">link</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="k">repeat</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="k">if</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="k">tell</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">links</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">joinList</span><span class="p">(</span><span class="nv">linkList</span><span class="p">,</span><span class="w"> </span><span class="s2">" "</span><span class="p">)</span><span class="w">
</span><span class="nb">set the clipboard to</span><span class="w"> </span><span class="nv">links</span><span class="w">
</span><span class="nb">display</span><span class="w"> </span><span class="nv">notification</span><span class="w"> </span><span class="s2">"Successfully Uploaded Screenshot and Copied the URL to the Clipboard"</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="na">title</span><span class="w"> </span><span class="s2">"Uploaded Finished"</span><span class="w"> </span><span class="na">sound</span><span class="w"> </span><span class="na">name</span><span class="w"> </span><span class="s2">"Purr"</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="nb">run</span><span class="w">
</span><span class="k">to</span> <span class="nv">joinList</span><span class="p">(</span><span class="nv">aList</span><span class="p">,</span><span class="w"> </span><span class="nv">delimiter</span><span class="p">)</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">retVal</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="s2">""</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">prevDelimiter</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">AppleScript</span>'s <span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">delimiters</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">AppleScript</span>'s <span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">delimiters</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">delimiter</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">retVal</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">aList</span><span class="w"> </span><span class="k">as </span><span class="nc">string</span><span class="w">
</span><span class="k">set</span><span class="w"> </span><span class="nv">AppleScript</span>'s <span class="nb">text</span><span class="w"> </span><span class="nb">item</span><span class="w"> </span><span class="nv">delimiters</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="nv">prevDelimiter</span><span class="w">
</span><span class="k">return</span><span class="w"> </span><span class="nv">retVal</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="nv">joinList</span><span class="w">
</span></code></pre></div></div>
Versioning in the URL?2014-03-20T00:00:00+00:00http://www.codeography.com/2014/03/20/hypermedia-api-versioned-url<p>After showing my friend <a href="http://github.com/guillec">Guille</a> the API I was working on he said:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>guillec: whats with the versioning in the URL?
guillec: dont talk to me
guillec: ever again
</code></pre></div></div>
<p>I love hypermedia APIs, so why do I have a version in the URL? Aren’t we supposed to version resources and not the entire API?</p>
<p>Well, I have my reasons.</p>
<p>But first, I do agree. This feels like a smell. If I see an API that does this I normally would make snarky comments. My gut tells me it is the result of poorly thought out API, a dated approach, or some other anti-pattern.</p>
<p>So, why do I put the version in the URL?</p>
<p>Because: It is hard to do things right.</p>
<p>So a little back story. A few constraints I have to work within. I am working at a little company on a small system that is being integrated by partners, often contractors or junior developers who just want to check it off a list and move on. So they want to crank out something with the minimum amount of work necessary.</p>
<p>Lets think about how they are going to use the API.</p>
<ul>
<li>They will cut corners</li>
<li>They will hard code URIs</li>
<li>They will not set the headers properly</li>
<li>They will assume the media type</li>
<li>They will complain if the API is hard to use</li>
<li>They will complain if something breaks (no matter how many corners they have cut)</li>
</ul>
<p>That’s all compleatly fair. I want to make their job easier, and I don’t want them to push back on integrating (lest an important deal fall through).</p>
<p>So now I think about what my goals are.</p>
<ul>
<li>I want to make it easy to integrate</li>
<li>I would prefer if the code behind it was clean and maintainable</li>
<li>I want my API to appear to be well thought out and properly designed (For example if Guille was evaluating my service, I want him to be impressed)</li>
<li>I need to be able to change the API as our product evolves</li>
</ul>
<p>A few constraints</p>
<p>I have been told by a few very smart and accomplished developers that the solution is to control the API and the client. But given my “little company/small system” I don’t have the cycles to create and maintain Ruby, Node, PHP, Java and ColdFusion libraries – and that’s just the clients we have now. So it needs to be a common denominator, which is the HTTP API.</p>
<p>The same goes for media types. I know I can correctly report the media type I support throught content negotiation, but by the time I get that far I’ve lost most developers. Also to save time and money I am only supporting one media type. Just dont’ have time to build out the others. Much less keep them all up to date. So effectively forcing a Hypermedia api into single media type. Not really ideal, but pragmatically what can be supported for now.</p>
<p>The compromise</p>
<p>Be as progressive as I can in the Hypermedia API. Pick a solid media type and stick to it. The point is to not reinvent new problems. HAL, JSON+collection, JSON API – just pick one that works for you.</p>
<p>Expect the consumer to cut corners. Plan for hard coded URLs. Resource IDs and URLs to be stored in their system. Improper use of headers such as content type, accepts, even authentication.</p>
<p>My Approach</p>
<ul>
<li>Handle the hardcoded URLs by versioning via the API</li>
<li>Force the content type to be JSON</li>
<li>Make it easy to Authorize
<ul>
<li>Authorization header (the documented and recomended way)</li>
<li>Session (logged in users can view the API in their browser)</li>
<li>Query Param (the It Just Works™ method, this way I email a url that will work for debugging or other support, but I don’t publish this in the docs)</li>
</ul>
</li>
</ul>
<p>I hope I can find a middle ground that will make the 9-to-5er happy as well as appease the zealous hypermedia advocate.</p>
<p>Things would be differnent with different constraints. The API is not stable, things will need to change. I don’t need many different representations of the resources. The clients consuming it will be the simpliset thing that works.</p>
<p>Are you using Hypermedia APIs in production and dealing with customers, zealots and unreasonable free loaders? I am curious how you handle this. Drop me a line or leave a comment.</p>
Ignoring people on IRC2014-03-19T00:00:00+00:00http://www.codeography.com/2014/03/19/ignore-user-or-nick-on-irc<p>Want to block, filter and ignore people (and bots) on IRC? Here’s what you do.</p>
<p>How to make #rspec on freenode usable.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/ignore GitHub*!*@*
</code></pre></div></div>
<p>Command Format:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/ignore nickname!username@userhost
</code></pre></div></div>
<p>Examples:</p>
<p>Match nicknames starting with “csex”:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/ignore csex*!*@*
</code></pre></div></div>
<p>Match the username “csexton”:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/ignore *!csexton@*
</code></pre></div></div>
<p>Match everyone on a .info domain:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/ignore *!*@*.info
</code></pre></div></div>
Ruby Retrocession Retrospective2014-02-03T00:00:00+00:00http://www.codeography.com/2014/02/03/ruby-retrocession-retrospective<p><img src="/images/retro4.jpg" style="width:100%" />
<span style="font-size: 60%">
Photo Credit: <a href="https://twitter.com/elight/status/429640778521276416">@elight</a>
<span></span></span></p>
<p>This last weekend Arlington Ruby hosted our semi regular unconference known as Ruby Retrocession. Or RetroRuby when you have a character limit.</p>
<p>As is normal in an Open Space event, we held a retrospective at the end. I thought it would be good to write some of that up. To help me remember, or perhaps help someone else who is participating or organizing something like this.</p>
<h2 id="moar-coffee">Moar Coffee</h2>
<p>We wanted to supply coffee, lunch and an after party/social event. We did this…mostly.</p>
<p>We had good coffee in the morning, but failed to get any for the afternoon. The morning Coffee came from Northside Social and was pretty tasty, we just got too caught up in running things that we should have delegated to someone to run and get things at the right time.</p>
<p>This brings up a good point. I think in the future I would find one volunteer who’s sole responsibility is coordinating food. They can delegate, but it’s their job to make sure it gets done. That person shouldn’t be doing anything else other than attending. They would also have a means to pay.</p>
<p>I had a blast picking up the tab for 100 of my closest friends at El Pollo Rico, but it would have been smarter to have someone else there to swipe the card.</p>
<h2 id="explain-better-up-front">Explain better up front</h2>
<p>The second most valuable feedback we had was to explain what the expectations are. With the format we had it is on the participants to get value out of the events. We needed to explain that better. A few points:</p>
<ul>
<li>Rule of two feet: If you are in a session and it is not helpful – get up and go. It’s not insulting to anyone for you to leave. It’s better to get up and wonder out than pull out the computer and reading email.</li>
<li>Coordinate smaller groups. If there something in particular you are interested in, or need help on – ask folks. See if you can get a little side group that can hack on something or discuss a narrower topic. This needed to be encouraged more. Perhaps some dedicated space for just this. Also a time for people to announce what they are working on or need help with.</li>
</ul>
<h2 id="structure-on-the-newbie-track-is-a-good-thing">Structure on the Newbie Track is a good thing</h2>
<p>The newbie track had much more structure, and it turns out that is a good thing. I had almost nothing to do with it (aside from being volentold to help with one of the sessions) and it was all <a href="http://twitter.com/allie_p">Allison</a> and <a href="http://twitter.com/kalimar">Kalimar</a>. They really did a fantastic job. All the feedback we got from the beginners was glowing. The only comments were that an in-between complete beginner (no clue about the command line) and beginner at ruby (programed before just new to the ruby eco system) would have been helpful for some folks.</p>
<h2 id="thanks">Thanks!</h2>
<p>To all the volunteers and sponsors we had this year, you guys rock. Thanks. Without your help we couldn’t have pulled this off.</p>
Use pow to serve your static html2014-01-17T00:00:00+00:00http://www.codeography.com/2014/01/17/using-pow-for-static-sites<p>I love <a href="http://pow.cx/">Pow</a>, and use it with Rails and Sinatra all the time. However I also maintain a few sites that are just plain old HTML files. Or generate plan old HTML files like Jekyll and Middleman.</p>
<p>I thought it would be nice to do local development on these using Pow, since it is on my machine already.</p>
<p>Turns out it is really easy.</p>
<ol>
<li>In <code class="highlighter-rouge">.pow</code> make a directory with the project name</li>
<li>Create a symlink called <code class="highlighter-rouge">public</code> to the static content</li>
</ol>
<p>Say I wanted to view this site locally at <code class="highlighter-rouge">http://codeography.dev/</code> this is what I would do:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~/.pow
mkdir codeography
ln -s ~/src/codeography/_site codeography/public
</code></pre></div></div>
<p>And now Pow will serve up the site locally for me at <code class="highlighter-rouge">http://codeography.dev</code>. Awesome.</p>
<h3 id="wait-wut">Wait, wut?</h3>
<p>How does this work?</p>
<p>Pow will serve static content from the public directory under your project. Normally you link to the top level directory and it happens to have a <code class="highlighter-rouge">public</code> folder contained – per the Rails convention. Well, I just tricked pow.</p>
<p>See, pow just looks in <code class="highlighter-rouge">~/.pow</code> for projects it can serve. It know to follow symlinks.</p>
<p>Instead of this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/.pow/(myproj --> ~/src/myproj)/public/index.html`
</code></pre></div></div>
<p>I just put make a folder and stick a public symlink:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/.pow/myproj/(public --> ~/src/myproj)/index.html`
</code></pre></div></div>
<p>Pretty handy little trick. And this way don’t have to remember which port Jekyll or Middleman uses.</p>
<p>You should remember this won’t re-generate your site if you are using tools like Jekyll and Middleman, you still have to run that manually.</p>
Most useful rake task for an idiot2013-12-19T00:00:00+00:00http://www.codeography.com/2013/12/19/rake-task-for-an-idiot<p>I am not the smartest. I frequently get things wrong. This is why I like programming, you can go fix things when you mess up. I would make a really bad surgon.</p>
<p>Given that, I love this rake task. I didn’t come up with the idea, but not sure exactly where it came from.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mespace</span> <span class="ss">:db</span> <span class="k">do</span>
<span class="n">task</span> <span class="ss">:dev_only</span> <span class="k">do</span>
<span class="k">raise</span> <span class="s2">"You can only use this in dev!"</span> <span class="k">unless</span> <span class="no">Rails</span><span class="p">.</span><span class="nf">env</span> <span class="o">==</span> <span class="s1">'development'</span>
<span class="k">end</span>
<span class="n">desc</span> <span class="s2">"Drop, create, migrate, seed the development database. Then prepare the test database."</span>
<span class="n">task</span> <span class="ss">fuckit: </span><span class="p">[</span>
<span class="s1">'environment'</span><span class="p">,</span>
<span class="s1">'db:dev_only'</span><span class="p">,</span>
<span class="s1">'db:reset'</span><span class="p">,</span>
<span class="s1">'db:seed'</span><span class="p">,</span>
<span class="s1">'db:test:prepare'</span>
<span class="p">]</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Now when you mess up your database, or get migrations out of sync you can just run <code class="highlighter-rouge">rake db:fuckit</code> and keep moving.</p>
iOS Frameworks with both 64 bit and 32 bit ARCHs2013-10-09T12:12:00+00:00http://www.codeography.com/2013/10/09/ios_frameworks_with_all_the_archs<p>I recently had to package up a static library for iOS as a framework bundle. This is something I had been doing for years for Mac application, but turned into a week long yak shave to get things working properly for iOS.</p>
<p>Originally I followed <a href="https://github.com/jverkoey/iOS-Framework">Jeff Verkoeyen’s iOS Framework</a> guide, however with the new 64 bit archetecutres that Apple introduced with the new iPhone this broke down.</p>
<p>The reason this broke down is because Xcode has a bit of magic when it comes to building the simulator target – it does some juju around the <code class="highlighter-rouge">ARCH</code>s it wants to build. And provides no way to edit that in the build settings gui that xcode has. Luckily I batteled this back when OS X learned how to speak with 64 bits, but there was some added complicaitons. Eventually I abandoned Jeff’s bash scripts in favor of ruby, due to the complexity of the entire thing.</p>
<p>To remember how this all works, and document it for my personal use in the future I put the scripts in a github repo, <a href="https://github.com/csexton/ios-framework-builder/">iOS Framework Buidler</a>. With the scripts in git I hope the community could help keep the scripts in tip top shape. They work great for me, but I am sure they could be more flexible and versitle.</p>
<p>If you need to build an iOS Framework Bundle, check out the <a href="https://github.com/csexton/ios-framework-builder/blob/master/HOWTO.md">How To Guide</a>.</p>
<p>Many thanks to Jeff Verkoeyen and the other folks to helped blaze the path to getting frameworks figured out.</p>
How I setup chruby2013-09-23T00:00:00+00:00http://www.codeography.com/2013/09/23/how_i_setup_chruby<p><strong>Update 8/13/2014: I updated the paths and the .zshenv script for latest version in homebrew</strong></p>
<p>After having another battle with pow and rvm I thought I would give <a href="https://github.com/postmodern/chruby">chruby</a> a go. So my little experiment went something like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew install chruby
brew install ruby-install
ruby-install ruby 1.9.3
ruby-install ruby 2.0
</code></pre></div></div>
<p>Then I load chruby in my <code class="highlighter-rouge">.zshenv</code> file.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">[[</span> <span class="nt">-f</span> /usr/local/opt/chruby/share/chruby/chruby.sh <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">source</span> /usr/local/opt/chruby/share/chruby/chruby.sh
<span class="nb">source</span> /usr/local/opt/chruby/share/chruby/auto.sh
<span class="k">else
</span><span class="nb">echo</span> <span class="s2">"Ain't got no chruby"</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>Fun Fact: We want to use the <code class="highlighter-rouge">.zshenv</code> and not the <code class="highlighter-rouge">.zshrc</code>. This is because <code class="highlighter-rouge">.zshrc</code> is for interactive shell configuration, whereas <code class="highlighter-rouge">.zshenv</code> is always sourced.</p>
<p>This should have you up and running now, but I have added two other steps to my normal process.</p>
<h3 id="bundler">Bundler</h3>
<p>First of all, for bundler I now use the <code class="highlighter-rouge">--path</code> option when I am first installing the gems for a project.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle install <span class="nt">--path</span> ./vendor/bundle
</code></pre></div></div>
<p>You only have to use that option once per project then bundler will remember where you put things (check out <code class="highlighter-rouge">.bundle/config</code> for details). But this is essentially the same thing I used RVM’s awesome gemsets for in the past.</p>
<h3 id="pow">Pow</h3>
<p>I use the hell out of the zero-conf web server <a href="http://pow.cx/">pow</a>. Now to configure the zero configure webserver I create a <code class="highlighter-rouge">.powenv</code> file in each of my projects that looks like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>source /usr/local/opt/chruby/share/chruby/chruby.sh
chruby $(cat .ruby-version)
</code></pre></div></div>
<p>According to the pow folks <code class="highlighter-rouge">.powrc</code> file are for checking into source control, and <code class="highlighter-rouge">.powenv</code> are for local settings.</p>
<hr />
<p>I am massivly grateful for RVM, and ruby wouldn’t be where it is today with out it. I love that project, and may go back to RVM. But for now I am seeing how a few lines of shell script can hold up. My only real complaint is having to use <code class="highlighter-rouge">ruby-install</code> or <code class="highlighter-rouge">ruby-build</code> or <code class="highlighter-rouge">curl/tar/make</code> when we already have homebrew.</p>
Sample post2013-08-20T00:00:00+00:00http://www.codeography.com/blog/2013/08/20/sample-post<p>Tattooed roof party <em>vinyl</em> freegan single-origin coffee wayfarers tousled, umami yr
meggings hella selvage. Butcher bespoke seitan, cornhole umami gentrify put a bird
on it occupy trust fund. Umami whatever kitsch, locavore fingerstache Tumblr pork belly
<a href="#">keffiyeh</a>. Chia Echo Park Pitchfork, Blue Bottle <a href="#">hashtag</a> stumptown skateboard selvage
mixtape. Echo Park retro butcher banjo cardigan, seitan flannel Brooklyn paleo fixie
Truffaut. Forage mustache Thundercats next level disrupt. Bicycle rights forage tattooed
chia, <strong>wayfarers</strong> swag raw denim hashtag biodiesel occupy gastropub!</p>
<hr />
<h1 id="its-all-in-the-game">It’s all in the game.</h1>
<h2 id="you-come-at-the-king-you-best-not-miss">You come at the king, you best not miss.</h2>
<h3 id="be-subtle-with-it-man-you-know-what-subtle-means">Be subtle with it, man. You know what subtle means?</h3>
<p>VHS post-ironic cred <strong>bespoke</strong> banjo. Yr wayfarers literally gentrify, flexitarian fap
dreamcatcher plaid cornhole Intelligentsia paleo. Beard try-hard direct trade, shabby chic
Helvetica <code class="highlighter-rouge">look ma, I can code</code>. Lo-fi American Apparel tattooed <a href="#">Vice</a> tofu, yr vinyl.
Williamsburg butcher hella mumblecore fixie mlkshk, cliche wolf keytar mixtape kitsch banh mi
salvia. High Life Odd Future <em>chambray</em> kale chips hoodie, cray pop-up. Helvetica narwhal
iPhone try-hard jean shorts.</p>
<blockquote>
<p>This is a quote from someone famous about productivity</p>
</blockquote>
<p>Syntax highlighting with Solarized theme.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">User</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">attr_accessible</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">:name</span>
<span class="o">...</span> <span class="n">tons</span> <span class="n">of</span> <span class="n">other</span> <span class="n">crap</span> <span class="o">...</span>
<span class="k">end</span></code></pre></figure>
Another sample2013-08-12T00:00:00+00:00http://www.codeography.com/blog/2013/08/12/another-sample<p>Tattooed roof party <em>vinyl</em> freegan single-origin coffee wayfarers tousled, umami yr
meggings hella selvage. Butcher bespoke seitan, cornhole umami gentrify put a bird
on it occupy trust fund. Umami whatever kitsch, locavore fingerstache Tumblr pork belly
<a href="#">keffiyeh</a>. Chia Echo Park Pitchfork, Blue Bottle <a href="#">hashtag</a> stumptown skateboard selvage
mixtape. Echo Park retro butcher banjo cardigan, seitan flannel Brooklyn paleo fixie
Truffaut. Forage mustache Thundercats next level disrupt. Bicycle rights forage tattooed
chia, <strong>wayfarers</strong> swag raw denim hashtag biodiesel occupy gastropub!</p>
<hr />
<h1 id="its-all-in-the-game">It’s all in the game.</h1>
<h2 id="you-come-at-the-king-you-best-not-miss">You come at the king, you best not miss.</h2>
<h3 id="be-subtle-with-it-man-you-know-what-subtle-means">Be subtle with it, man. You know what subtle means?</h3>
<p>VHS post-ironic cred <strong>bespoke</strong> banjo. Yr wayfarers literally gentrify, flexitarian fap
dreamcatcher plaid cornhole Intelligentsia paleo. Beard try-hard direct trade, shabby chic
Helvetica <code class="highlighter-rouge">look ma, I can code</code>. Lo-fi American Apparel tattooed <a href="#">Vice</a> tofu, yr vinyl.
Williamsburg butcher hella mumblecore fixie mlkshk, cliche wolf keytar mixtape kitsch banh mi
salvia. High Life Odd Future <em>chambray</em> kale chips hoodie, cray pop-up. Helvetica narwhal
iPhone try-hard jean shorts.</p>
<blockquote>
<p>This is a quote from someone famous about productivity</p>
</blockquote>
<p>Syntax highlighting with Solarized theme.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">User</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">attr_accessible</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">:name</span>
<span class="o">...</span> <span class="n">tons</span> <span class="n">of</span> <span class="n">other</span> <span class="n">crap</span> <span class="o">...</span>
<span class="k">end</span></code></pre></figure>
Remapping Caps Lock was only the Beginning2013-06-26T00:00:00+00:00http://www.codeography.com/2013/06/26/remapping-caps-lock-was-only-the-beginning<p>It seems that remapping caps lock has finally caught on. The only valid(ish) argument I see happening is which key to remap it to. I have been firmly in the camp that it should be remapped to <code class="highlighter-rouge">control</code> however, there seems to be a strong contengent of people who inisit it should be <code class="highlighter-rouge">esc</code>. Aside from them being wrong, it occurs to me that reaching up for <code class="highlighter-rouge">esc</code> was a bit of a stretch. So why not both.</p>
<p>I want <code class="highlighter-rouge">caps lock</code> to be control when pressed with another key, and <code class="highlighter-rouge">esc</code> when pressed alone.</p>
<p>Well linux folks got <a href="https://github.com/alols/xcape">xcape</a>, and us mac fans have <a href="https://pqrs.org/macosx/keyremap4macbook/">keyremap4macbook</a>. It just was a little round about to make <code class="highlighter-rouge">caps lock</code> be dual function (neither of which was the original function)</p>
<p>First, configure <code class="highlighter-rouge">caps lock</code> to be control with <a href="/2010/12/02/remap-capslock-to-control-on-a-mac.html">System Preferences -> Keyboard -> Modifier Keys…</a></p>
<p>Now that it done, go grab a copy of keyremap4macbook, install it and run it.</p>
<p>When it first launches you will see a list of a bajillion options.</p>
<p><img src="/images/capslock-02.png" alt="keyremap4macbook" /></p>
<p>You can either scroll down looking for “Control_L” or just search for “Control_L escape”</p>
<p><img src="/images/capslock-03.png" alt="keyremap4macbook" /></p>
<p>Now you can check the box that reads “Control_L to Control_L (+ When you type Control_L only, send Escape)”</p>
<p>You should be set. Now you just have to retrain you hands to stop reaching for <code class="highlighter-rouge">esc</code> all the time.</p>
<h3 id="bonus">Bonus:</h3>
<p>I also like to change the right <code class="highlighter-rouge">command</code> key to act at <code class="highlighter-rouge">enter</code> when pressed alone. I think it is a little bit easier on my hands to mash that with my thumb in leu of the pinky reaching over to the normal <code class="highlighter-rouge">enter</code> key.</p>
<p><img src="/images/capslock-04.png" alt="keyremap4macbook" /></p>
<p>keyremap4macbook does a ton of other very cool tricks, explore and see what works for you. If you find something cool <a href="http://twitter.com/crsexton">let me know</a>.</p>
Navigating Vim and Tmux Splits2013-06-19T00:00:00+00:00http://www.codeography.com/2013/06/19/navigating-vim-and-tmux-splits<p>So I read this awesome blog post on the <a href="http://robots.thoughtbot.com/post/53022241323/seamlessly-navigate-vim-and-tmux-splits">Thoughtbot Blog</a>, that was just a write up of <a href="https://gist.github.com/mislav/5189704">Mislav’s technique</a>, but it didn’t work for me. Disallusioned and desolate I figured my fate was sealed. I would have to navigate splits in two totally different ways.</p>
<p>But what’s this? <a href="https://github.com/aaronjensen">Aaron Jensen</a> has another solution? Yes. Yes, he does. Does this one work? Like the wind.</p>
<p>This code is almost entirely taken from Aaron’s dot files (see <a href="https://github.com/aaronjensen/vimfiles/blob/66b7da914b403c7885db87123068c1f7dc71c0eb/vimrc#L468-L502">vimrc</a> and <a href="https://github.com/aaronjensen/dotfiles/blob/ebfacc5fba0eca45c592e465e6ed211350a4bce2/tmux.conf#L103-L109">tmux.conf</a>). I am putting it here so i have things all in one place that I can find later when I want to set this up again.</p>
<p>Add this to your <code class="highlighter-rouge">.tmux.conf</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">bind</span> <span class="nt">-n</span> C-h run <span class="s2">"(tmux display-message -p '#{pane_title}' | grep -iq vim && tmux send-keys C-h) || tmux select-pane -L"</span>
<span class="nb">bind</span> <span class="nt">-n</span> C-j run <span class="s2">"(tmux display-message -p '#{pane_title}' | grep -iq vim && tmux send-keys C-j) || tmux select-pane -D"</span>
<span class="nb">bind</span> <span class="nt">-n</span> C-k run <span class="s2">"(tmux display-message -p '#{pane_title}' | grep -iq vim && tmux send-keys C-k) || tmux select-pane -U"</span>
<span class="nb">bind</span> <span class="nt">-n</span> C-l run <span class="s2">"(tmux display-message -p '#{pane_title}' | grep -iq vim && tmux send-keys C-l) || tmux select-pane -R"</span>
</code></pre></div></div>
<p>And add this to your <code class="highlighter-rouge">.vimrc</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if exists('$TMUX')
function! TmuxOrSplitSwitch(wincmd, tmuxdir)
let previous_winnr = winnr()
silent! execute "wincmd " . a:wincmd
if previous_winnr == winnr()
call system("tmux select-pane -" . a:tmuxdir)
redraw!
endif
endfunction
let previous_title = substitute(system("tmux display-message -p '#{pane_title}'"), '\n', '', '')
let &t_ti = "\<Esc>]2;vim\<Esc>\\" . &t_ti
let &t_te = "\<Esc>]2;". previous_title . "\<Esc>\\" . &t_te
nnoremap <silent> <C-h> :call TmuxOrSplitSwitch('h', 'L')<cr>
nnoremap <silent> <C-j> :call TmuxOrSplitSwitch('j', 'D')<cr>
nnoremap <silent> <C-k> :call TmuxOrSplitSwitch('k', 'U')<cr>
nnoremap <silent> <C-l> :call TmuxOrSplitSwitch('l', 'R')<cr>
else
map <C-h> <C-w>h
map <C-j> <C-w>j
map <C-k> <C-w>k
map <C-l> <C-w>l
endif
</code></pre></div></div>
<p>The cool thing about this approach is that vim detects if it is running in tmux and will set the pane title. Then tmux will inspect the pane title when you try to switch and pass the key press on through. I think Mislav’s approach wasn’t working for me because tmux would intercept the key before vim had a chance.</p>
Replacing All The Things with Unite.vim2013-06-17T00:00:00+00:00http://www.codeography.com/2013/06/17/replacing-all-the-things-with-unite-vim<h4 id="or-unites-killer-feature">Or: Unite’s Killer Feature</h4>
<p>Recently started using <a href="https://github.com/Shougo/unite.vim">Unite.vim</a> and have really been liking it. I found it through a blog post by <a href="http://bling.github.io//blog/2013/06/02/unite-dot-vim-the-plugin-you-didnt-know-you-need/#comment-919769841">Bailey Ling</a> where he describes how he replaced a number of his plugins with Unite. So I gave it a go, and sure enough I was able to replace Command-T, Yankstack and BufExplorer.</p>
<p>That last one surprised even me, I’ve been using BufExplorer for more than a decade and swore I was never gonna give it up.</p>
<p>First my rationale behind loving this lil plugin. Not only is it a powerful interface for navigating my code, but it is a consistant interface. Once I get the muscle memory for navigating one thing (say buffers), I can use that to navigate all the things (say yank history).</p>
<p>And the other, and this was killer for me, it can be modal. This doesn’t sound like a big deal, but I feel this is how vim is supposed to work – it is a modal editor dammit. Instead of popping open a split for the search list at the top or bottom of the window, Unite can be told to open in the active pane. This means when you invoke it unite will open in the pane you are operating on. Which is what I care about. No guessing, it just pops open right where I was looking to start with.</p>
<p>To show you what I mean:</p>
<div class="vimwin">
<div class="vimhead"> VIM </div>
<div class="vimbody"><img src="/images/unite-modal-c.gif" /></div>
</div>
<p>One of the things I like about unite is that it does not come with default keybindings out of the box. You have to (you get to?) set them up yourself. But starting with a good example never hurts, so here is what I have in my <code class="highlighter-rouge">.vimrc</code> if you would like some insperation:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>" Unite
let g:unite_source_history_yank_enable = 1
call unite#filters#matcher_default#use(['matcher_fuzzy'])
nnoremap <leader>t :<C-u>Unite -no-split -buffer-name=files -start-insert file_rec/async:!<cr>
nnoremap <leader>f :<C-u>Unite -no-split -buffer-name=files -start-insert file<cr>
nnoremap <leader>r :<C-u>Unite -no-split -buffer-name=mru -start-insert file_mru<cr>
nnoremap <leader>o :<C-u>Unite -no-split -buffer-name=outline -start-insert outline<cr>
nnoremap <leader>y :<C-u>Unite -no-split -buffer-name=yank history/yank<cr>
nnoremap <leader>e :<C-u>Unite -no-split -buffer-name=buffer buffer<cr>
" Custom mappings for the unite buffer
autocmd FileType unite call s:unite_settings()
function! s:unite_settings()
" Play nice with supertab
let b:SuperTabDisabled=1
" Enable navigation with control-j and control-k in insert mode
imap <buffer> <C-j> <Plug>(unite_select_next_line)
imap <buffer> <C-k> <Plug>(unite_select_previous_line)
endfunction
</code></pre></div></div>
<p>Hopefully this gives you a decent place to start building an awesome vimming rig. With extra modal.</p>
install macvim with lua support2013-06-11T00:00:00+00:00http://www.codeography.com/2013/06/11/install-macvim-with-lua-support<p>If you use the amazing <a href="https://github.com/Shougo/unite.vim">unite.vim</a> plugin and noticed it being anything less than snappy, then you need to make sure you have vim with lua support enabled.</p>
<p>You can see if you copy of vim has it enabled by running <code class="highlighter-rouge">:version</code> and looking for <code class="highlighter-rouge">+lua</code>. If you see <code class="highlighter-rouge">-lua</code> it is not enabled. The main download binary for MacVim does not have it enabled.</p>
<p>The solution for this is simple, install MacVim from Homebrew with the <code class="highlighter-rouge">--with-lua</code> flag. The exact command I use is:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew install macvim --with-cscope --with-lua --override-system-vim
</code></pre></div></div>
<p>That will install with lua and cscope, and will put a symlink in <code class="highlighter-rouge">/usr/local/bin</code> that will shadow your system command line vim. All good things. To see the other options check out the <a href="https://github.com/mxcl/homebrew/blob/master/Library/Formula/macvim.rb">homebrew formula</a>.</p>
Fancy tmux keybindings with iTerm2013-05-16T00:00:00+00:00http://www.codeography.com/2013/05/16/tmux-iterm-keybindings<p>I wanted to bind <code class="highlighter-rouge">⌘-{</code> and <code class="highlighter-rouge">⌘-}</code> to switch windows in tmux (window is to tmux <em>as</em> tab is to everything else). Turns out tmux won’t let you <a href="http://superuser.com/a/259622/70029">bind to ⌘</a>. I was able to solve this with a little hack in iTerm.</p>
<p>In iTerm preferences, click Profiles in the toolbar, then the Keys tab. You’ll see a lieelte <code class="highlighter-rouge">+</code> button there:</p>
<p><img src="/images/tmux-keybindings-01.png" /></p>
<p>Click in the “Keyboard Shortcut” field, and mash the shortcut you want to use (in my case <code class="highlighter-rouge">command-shift-[</code>).</p>
<p>Here is the real trick, choose “Send Hex Code” as the action.</p>
<p><img src="/images/tmux-keybindings-02.png" /></p>
<p>Then in the field you want to enter the <a href="http://www.columbia.edu/kermit/ascii.html">ascii code</a> for what you want to send to tmux. In my case I used:</p>
<table style="background-color: #efefef;">
<thead>
<tr>
<th>Key Binding</th>
<th>Hex Code</th>
<th>Keys Sent</th>
<th>tmux command</th>
</tr>
</thead>
<tbody>
<tr>
<td> <code>⌘-{</code> </td>
<td> <code>0x02 0x70</code> </td>
<td> <code>control-b,p</code> </td>
<td> previous window </td>
</tr>
<tr>
<td> <code>⌘-}</code> </td>
<td> <code>0x02 0x6E</code> </td>
<td> <code>control-b,n</code> </td>
<td> next window </td>
</tr>
</tbody>
</table>
<p>The other thing that makes this easier to keep tmux and iterm working nicely is to use the <code class="highlighter-rouge">prefix2</code> setting in tmux. That lets you keep <code class="highlighter-rouge">control-b</code> working as a prefix binding, but you can also use a more comfortable binding when you are typing.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Set C-f to prefix, but leave C-b in place
set -g prefix2 C-f
bind C-f send-prefix
bind C-f last-window
</code></pre></div></div>
<p>I think this is a nice little trick that would work for more things than just tmux. Let me know if you find other clever uses for it.</p>
Apache, Passenger and mod rewrite2013-03-22T00:00:00+00:00http://www.codeography.com/2013/03/22/apache-passenger-and-mod-rewrite<p>After spending entirely too much time batteling with <code class="highlighter-rouge">mod_rewrite</code> I figured I would document how I solved my problem.</p>
<p>Basically I wanted different paths for my apis based on the host name. Turns out the hard part was figuring out how to convince apache to rewrite the urls so that Rails would be happy. Here is the entire apache config file (aside from the ssl and assets VirtualHosts):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Passenger
LoadModule passenger_module /usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.18/ext/apache2/mod_passenger.so
PassengerRoot /usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.18
PassengerRuby /usr/local/bin/ruby_with_env
<VirtualHost *:80>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^api [NC]
RewriteCond %{REQUEST_URI} !^/api [NC]
RewriteRule ^/(.*) /api/$1 [PT,L,QSA]
</IfModule>
ServerName app.messageradius.com
DocumentRoot /var/www/passenger/current/public
<Directory /var/www/passenger/current/public>
AllowOverride all
Options -MultiViews
</Directory>
</VirtualHost>
</code></pre></div></div>
<p>The break down:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RewriteCond %{HTTP_HOST} ^api [NC]
</code></pre></div></div>
<p>This matches any domains that start with “api”</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RewriteCond %{REQUEST_URI} !^/api [NC]
</code></pre></div></div>
<p>This will match any paths that do not start with “/api”</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RewriteRule ^/(.*) /api/$1 [PT,L,QSA]
</code></pre></div></div>
<p>Here is the part that too me so much effort. The <a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html">options passed into the RewriteRule</a>. You need at least <code class="highlighter-rouge">PT</code> and <code class="highlighter-rouge">L</code> for Passenger to mangle the url and pass it to your app.</p>
<ul>
<li><code class="highlighter-rouge">PT</code> - Forces the resulting URI to be passed back to the URL mapping engine for processing of other URI-to-filename translators</li>
<li><code class="highlighter-rouge">L</code> - Stop the rewriting process immediately and don’t apply any more rules.</li>
<li><code class="highlighter-rouge">QSA</code> - Appends any query string from the original request URL to any query string created in the rewrite target.</li>
</ul>
<p>I went ahead an added <code class="highlighter-rouge">QSA</code> to merge query parameters. I am not sure it is required, but seems to work.</p>
localtime directive for angularjs2013-02-26T00:00:00+00:00http://www.codeography.com/2013/02/26/localtime-directive-for-angularjs<style>
localtime {
background-color: #efefef;
border: thin solid black;
margin: 1em;
padding: 1em;
border-radius: 4px;
}
</style>
<p>A little while back I wrote about a <a href="http://www.codeography.com/2012/10/11/convert-timestamps-localtime-jquery.html">jQuery plugin</a> I had that would convert UTC time stamps to the local timezone of the browser. Since then I have been experimenting a bit with <a href="http://angularjs.org/">AngularJS</a> and wanted the same thing but in an angly way. Here is my attempt at porting that code over.</p>
<p>First I made a module that declared a directive:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@angular.module('localtime').directive 'localtime', ->
# Makes a string with only two characters, adding a leading zero
fmtZero = (str) ->
('0' + str).slice(-2)
# This is the function to change if you want to customize the format of the date
fmtDate= (d) ->
# format the date
hour = d.getHours()
if hour < 12
meridiem = "AM"
else
meridiem = "PM"
hour = 12 if hour is 0
hour = hour - 12 if hour > 12
hour + ":" + fmtZero(d.getMinutes()) + " " + meridiem + " " + (d.getMonth()+1)+ "/" + d.getDate() + "/" + d.getFullYear()
restrict: 'E'
link: (scope, element, attrs) ->
tagText = element.html()
element.html fmtDate(new Date(tagText))
element.attr "title", tagText
</code></pre></div></div>
<p>The real magic is in the <code class="highlighter-rouge">link</code> function that grabs the current html content for the element and overwrites it. To help with debugging I stick the original timestamp in the <code class="highlighter-rouge">title</code> attribute – which you can see when you mouse over a date.</p>
<p>Then in my angular app, I just include the module:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@myApp = angular.module('myApp', ['localtime'])
</code></pre></div></div>
<p>Now, in my markup I simply wrap the timestamps I care about in <code class="highlighter-rouge"><localtime></code> tags and they get switched over to a nicely formatted string in the user’s local time zone.</p>
<p>The end result is a timestamp string going from this:</p>
<p><localtime>2013-02-26T17:53:00+00:00</localtime></p>
<p>To this:</p>
<p><localtime title="2013-02-26T17:53:00+00:00">12:53 PM 2/26/2013</localtime></p>
Vim - highlight debugger statements2013-02-10T00:00:00+00:00http://www.codeography.com/2013/02/10/vim-never-check-in-a-debugger-statement-again<p><img src="/images/vim-debugger.png" /></p>
<p>I know some folks thoroughly disapprove of using debugger, but in the context of a big app, using a framework or libraries you didn’t write I find them crazy helpful. Plus you can drop into your unit tests to track down a failure so easy.</p>
<p>My problem is I have been known to check in code that has a debugger statement. Only to end up with a git log like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>* 0f93265 Remove debugging statements.
</code></pre></div></div>
<p>I used a git pre-commit hook for a while to stop me from checking bad things in, and that did the job but I found it to be jarring. Really what I needed was to make it painfully obvious when I had dropped one into my code. This gets the job done nicely in vim:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>" Make those debugger statements painfully obvious
au BufEnter *.rb syn match error contained "\<binding.pry\>"
au BufEnter *.rb syn match error contained "\<debugger\>"
</code></pre></div></div>
<p>Also in a <a href="https://gist.github.com/csexton/4742417">gist</a>.</p>
Source Maps with Chrome Canary and Rails2012-12-08T00:00:00+00:00http://www.codeography.com/2012/12/08/source-maps-with-chrome-canary-and-rails-3<p>I was having problem piecing together all the steps to enabling source maps in Chrome Canary. I really wanted to get it working with the rails-sass gem that comes with Rails 3, and the Asset Pipeline.</p>
<p>Eventually I got things working, this is what I did:</p>
<h2 id="step-1">Step 1:</h2>
<p>In <a href="https://tools.google.com/dlpage/chromesxs">Chrome Canary</a> navigate to <code class="highlighter-rouge">chrome://flags/</code></p>
<h2 id="step-2">Step 2:</h2>
<p>Search for “Developer Tools experiments” and enable</p>
<p><img src="/images/source-map-01.png" /></p>
<h2 id="step-3">Step 3:</h2>
<p>Enable sass support in the developer tools:</p>
<ol>
<li>View->Developer->Developer Tools.</li>
<li>Click the gear in the bottom right.</li>
<li>Choose the Experimental Tab.</li>
</ol>
<p>Settings:</p>
<p><img src="/images/source-map-02.png" /></p>
<p>Experiments tab:</p>
<p><img src="/images/source-map-03.png" /></p>
<h2 id="step-4">Step 4:</h2>
<p>In <code class="highlighter-rouge">config/enviroments/development.rb</code> Add <code class="highlighter-rouge">config.sass.debug_info = true</code> inside the <code class="highlighter-rouge">Application.configure</code> block.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MyApp::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# ...
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
# Enable source maps in the browser
config.sass.debug_info = true
end
</code></pre></div></div>
<p>This should cause rails-sass to include the <code class="highlighter-rouge">@media -sass-debug-info</code> statements in your generated application.css file. I found it helpful to visit <code class="highlighter-rouge">/assets/application.css</code> directly on the rails app to make sure that was working.</p>
<h2 id="step-5">Step 5:</h2>
<p>Reboot all the things. Reload rails server. Reload the browser.</p>
<h2 id="step-6">Step 6:</h2>
<p>Now the developer tools links to your sass files directly. Huzzah!</p>
<p><img src="/images/source-map-04.png" /></p>
Convert timestamps to localtime with jQuery2012-10-11T00:00:00+00:00http://www.codeography.com/2012/10/11/convert-timestamps-localtime-jquery<p>Dealing with dates and times is a real pain. Everything is an edgecase. Having lived through a good deal of pain working with this suff I have made a rule: All times stored in the database shall be in UTC.</p>
<p>This makes many things much easier, but that sure makes for ugly dates to show an end user. And more importantly I can never do the conversion in my head between timezones. I just think in my local timezone, and in a 12 hour clock. So I would like to see my dates that way.</p>
<p>There are other solutions for this out there, but many of them involve too much gymnastics. I don’t want to make a TimeZoneOffset controller and inject a bit of JS into my page to post to it and set a session variables. I don’t want to store the user’s timezone in the database. And really I don’t want my server converting 1000’s of timestamps when I could have the browser do it for me.</p>
<p>So my solution was to write a jQuery plugin. Add a little view helper to keep things clean.</p>
<p>The code:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(function() {
(function($) {
return $.fn.localtime = function() {
var fmtDate, fmtZero;
fmtZero = function(str) {
return ('0' + str).slice(-2);
};
fmtDate = function(d) {
var hour, meridiem;
hour = d.getHours();
if (hour < 12) {
meridiem = "AM";
} else {
meridiem = "PM";
}
if (hour === 0) { hour = 12; }
if (hour > 12) { hour = hour - 12; }
return hour + ":" + fmtZero(d.getMinutes()) + " " + meridiem + " " + (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
};
return this.each(function() {
var tagText;
tagText = $(this).html();
$(this).html(fmtDate(new Date(tagText)));
return $(this).attr("title", tagText);
});
};
})(jQuery);
}).call(this);
</code></pre></div></div>
<p>This was originally written in coffeescript, so grab <a href="https://gist.github.com/3874031">that</a> if you prefer.</p>
<p>Load the plugin, and have it find the matching tags in your document ready block:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$(document).ready(function() {
$("span.localtime").localtime();
});
</code></pre></div></div>
<p>Then you just wrap dates in a span with class of ‘localtime’:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="localtime">2012-10-10T06:42:47Z</span>
</code></pre></div></div>
<p>And the dates get converted to this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="localtime" title="2012-10-10T06:42:47Z">2:42 AM 10/10/2012</span>
</code></pre></div></div>
<p>Which looks nice and readable to me:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2:42 AM 10/10/2012
</code></pre></div></div>
<p>Adding a little sugar - View helper</p>
<p>I wanted to keep my markup nice an neat so I made a <code class="highlighter-rouge">localtime_tag</code> helper to clean things up a little. Since ECMA Script can parse ISO 8601 Date strings, I used ruby’s handy Time#iso8601 method. Here is how I implemented it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def localtime_tag(time)
time = Time.parse(time) unless time.respond_to? :utc
formatted_str = time.utc.iso8601
content_tag :span, formatted_str, class: 'localtime'
end
</code></pre></div></div>
<p>If you are not using rails you may need to <code class="highlighter-rouge">require "time"</code> to get the iso8601 method.</p>
<p>It will take the date and format it into a timestamp that will include timezone so that the JS <code class="highlighter-rouge">Date</code> parser will be able to convert it to the local time.</p>
Howto setup the Ultimate IRC Server2012-09-23T00:00:00+00:00http://www.codeography.com/2012/09/23/howto-irc-server<p>While I like Campfire and HipChat and those other tools for group collaboration there is just something nice about using an IRC channel. Probably the most compelling reason is that I am going to have my IRC client running anyway for other channels – so it would be nice to just add a server and use the same client I am already using.</p>
<p>At Radius we had been using a public server for a little bit of communication, but the converstaions starting becoming more technical and wasn’t happy having things go through someone else’s server, and be unencrypted. So I decided to setup my own. I give you the ultimate irc setup:</p>
<h2 id="the-ultimate-irc-server">The Ultimate IRC Server</h2>
<p>The ultimate server consists of a few components:</p>
<ul>
<li>The IRC server itself (ircd-hybrid)</li>
<li>an IRC bouncer (ZNC)</li>
<li>a way to tunnel port 443 to the bouncer</li>
<li>and maybe a bot that can post funny pictures of cats for you</li>
</ul>
<p>I am using Ubuntu Server 12.04.1 LTS (ami-137bcf7a) running on a micro instance.</p>
<h3 id="install-the-irc-server">Install the IRC Server</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install ircd-hybrid
sudo vim /etc/ircd-hybrid/ircd.motd
</code></pre></div></div>
<p>Create the password required to be the Oper:</p>
<p><em>WARNING: Please do not mix up the <code class="highlighter-rouge">mkpasswd</code> program from <code class="highlighter-rouge">/usr/sbin</code> with this one. If you are root, typing <code class="highlighter-rouge">mkpasswd</code> will run that one instead and you will receive a strange error.</em></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/bin/mkpasswd super-secret
</code></pre></div></div>
<p>Edit the config file, this is well documented and there are plenty of little tweaks you can make but make a couple little changes now:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo vim /etc/ircd-hybrid/ircd.conf
</code></pre></div></div>
<p>Comment out the <code class="highlighter-rouge">host</code> parameter in the <code class="highlighter-rouge">listen</code> section (about line 130 in the default ubuntu config)</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>host = “127.0.0.1″;
</code></pre></div></div>
<p>to be</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#host = “127.0.0.1″;
</code></pre></div></div>
<p>And increase the <code class="highlighter-rouge">max_clients</code> in the <code class="highlighter-rouge">serverinfo</code> section:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>max_clients = 2;
</code></pre></div></div>
<p>to be</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>max_clients = 512;
</code></pre></div></div>
<p>This will open the server up to external connections (Note: make sure you configure your instance to have these ports open, e.g. in EC2 you will need to edit the security profile and open ports 443, 6664, and 6667), and allow more than 2 folks to connect from the same IP (which is important since we will have everyone connect via ZNC running on this machine).</p>
<p>Now restart the server</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /etc/init.d/ircd-hybrid restart
</code></pre></div></div>
<p>Now you should be able to fire up your favorite client and see if you can get it to connect to the server. Once you have proven it works, time to move onto the bouncer.</p>
<h3 id="install-the-irc-bouncer">Install the IRC Bouncer</h3>
<p>Originally I followed the guide from <a href="http://www.nerdydork.com/setting-up-a-znc-irc-bouncer.html">Dustin Davis</a> but have a few tweaks:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install znc
znc --makeconf
</code></pre></div></div>
<p>Follow the guides to setup the server. I mostly choose the defaults, and enabled all the modules</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>What port would you like ZNC to listen on? (1025 to 65535): 6664
Would you like ZNC to listen using SSL? (yes/no) [no]: yes
Would you like to create a new pem file now? (yes/no) [yes]: yes
Listen Host (Blank for all ips):
Number of lines to buffer per channel [50]: 1000
Would you like to keep buffers after replay? (yes/no) [no]: yes
</code></pre></div></div>
<p>Configure ZNC to use the brand new IRC server that we just installed:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IRC server (host only): 127.0.0.1
[127.0.0.1] Port (1 to 65535) [6667]: 6667
[127.0.0.1] Password (probably empty):
Does this server use SSL? (yes/no) [no]:
Would you like to add another server for this IRC network? (yes/no) [no]: no
Would you like to add a channel for ZNC to automatically join? (yes/no) [yes]: yes
Would you like to add another channel? (yes/no) [no]: no
Would you like to set up another user (e.g. for connecting to another network)? (yes/no) [no]: no
Launch ZNC now? (yes/no) [yes]: no
</code></pre></div></div>
<p>Now you can run ZNC as that user and verify it works, and make tweaks to the config.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vi .znc/configs/znc.conf
</code></pre></div></div>
<p>or with the webadmin module by pointing a browser to</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://yourhostname:6664
</code></pre></div></div>
<p>To verify that this works with your local client you should just have to change the port from 6667 to 6664. If you want to compare settings my initial config file looked something like <a href="https://gist.github.com/3773180">this</a>.</p>
<h3 id="make-znc-a-system-daemon">Make ZNC a system daemon</h3>
<p>At the end of the config keep it running and connect to it from your local IRC client to make sure things are working. Once you have proven it works time to set it up as a daemon that starts at boot. I used Henner’s <a href="http://doomclaw.de/index.php/2009/08/18/run-znc-at-boot-with-an-init-script/">guide</a> when I first set this up.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>killall znc # just to make sure
</code></pre></div></div>
<p>Create the user and group</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo addgroup --system znc
sudo adduser --system --no-create-home --ingroup znc znc
</code></pre></div></div>
<p>Create the init script, I have the one I use up <a href="https://gist.github.com/3772971">here</a></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo vim /etc/init.d/znc
</code></pre></div></div>
<p>It’s pretty big, so you may want to curl it down</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl https://gist.githubusercontent.com/csexton/3772971/raw/efbe88004be70cb7f157e30aa1183ea5867d8de6/gistfile1.sh > /etc/init.d/znc
</code></pre></div></div>
<p>Copy over the ZNC config files to <code class="highlighter-rouge">/etc</code>, and update permissions</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir /etc/znc
sudo mv /home/$USER/.znc/* /etc/znc/
rm -R /home/$USER/.znc
chown -R znc:znc /etc/znc
sudo chown -R znc:znc /etc/znc
sudo chmod +x /etc/init.d/znc
</code></pre></div></div>
<p>Start ‘er up</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /etc/init.d/znc start
</code></pre></div></div>
<h3 id="setup-port-forwarding">Setup port forwarding</h3>
<p>Forward from 443 to 6664 to work around firewalls.</p>
<p>This step is not required if your network does not block the ports we are using. But it is still nice to use in case you ever find yourself on one. Also you would not want to do this on a server that is serving webpages over https.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install rinetd
sudo vim /etc/rinetd.conf
</code></pre></div></div>
<p>Edit that file to include a new forwarding rule</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.0.0.0 443 127.0.0.1 6664
</code></pre></div></div>
<p>Restart rinetd</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /etc/init.d/rinetd restart
</code></pre></div></div>
<p>If you enabled the webadmin module in ZNC you should now be able to point your browser to <code class="highlighter-rouge">https://yourhostname</code> and edit your ZNC config (and let folks edit their accounts, configure modules and change passwords). Yes, ZNC uses the same port for IRC connections and for the admin page.</p>
<h3 id="recap">Recap</h3>
<p>Now you should have an irc server running on port 6667, a bouncer running on port 6664, and a tunnel for the bouncer from port 443.</p>
<p>I just used the web admin module to setup accounts for everyone on my team. I wound up turning off external access to 6667 so that I didn’t have to secure ircd, and everyone just goes through ZNC.</p>
<p>You might want to setup an bot to do your bidding, I use <a href="http://github.com/csexton/radbot">radbot</a>. You should fork :-)</p>
<p>I run this on a micro instance on Amazon’s EC2, so it costs us about $14/month – but given that I use the server for other things as well it doesn’t <em>really</em> cost the full $14.</p>
Mobile Safari Inspector with the iPhone Simulator2012-03-30T00:00:00+00:00http://www.codeography.com/2012/03/30/remote-debugging-mobile-safari-inspector-ios-simulator<p>Thanks in large part do other folks (well, mostly <a href="http://atnan.com/blog/2011/11/17/enabling-remote-debugging-via-private-apis-in-mobile-safari/">Nathan</a>) who dug in and figured out the private API to enable this in WebKit, we can actually use the web inspector from the desktop Safari browser to investigate pages we are viewing on the iPhone simulator. This has been huge when I have a strange bug in the layout of a page on the iPad and can’t easily determine which element it is.</p>
<p>Here is my version of the script that takes things a bit further:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pid=$(ps x | egrep "MobileSafari|Web.app" | grep -v grep | awk '{ print $1 }')
if [ "$pid" == "" ]; then
echo "Safari.app must be running in the Simulator to enable the remote inspector."
else
cat <<EOS | gdb -quiet > /dev/null
attach $pid
p (void *)[WebView _enableRemoteInspector]
detach
EOS
osascript <<EOS > /dev/null 2>&1
tell application "Safari"
activate
do JavaScript "window.open('http://localhost:9999')" in document 1
end tell
EOS
fi
</code></pre></div></div>
<p>Since I use chrome as my default browser, I quickly found that the remote inspector didn’t always work with it - so I open safari automatically and load the inspector. Just one less step to worry about. I wanted to have it open the simulator and run Safari as well, but that turned out to require other tools to be installed so I punted. This is really the most common case for me anyway.</p>
<p>If you want a copy locally I recommend grabbing the one from my <a href="https://github.com/csexton/dotfiles/blob/master/bin/mobile-safari-inspector">dotfiles</a>, which I will keep up-to-date if I make any tweaks and changes.</p>
Vimscript is Super Awesome2012-02-20T00:00:00+00:00http://www.codeography.com/2012/02/20/vimscript-is-super-awesome<p>OK, sure it could be a little prettier, and yeah, it make simple things awkward. But it has one killer feature that I think is often overlooked. Vimscript uses the same commands that you use when editing a file.</p>
<p>This is actually really cool. Basically if you can do something while using the editor you can do it in a script. Think about that, you can really automate everything you already do, and since you already do it–you know how to automate it. The inverse is true as well, if you read it in a script you can do that while editing.</p>
<p>A quick example. Strip trailing white space. I’ve done this often, open a file with a ton of garbage whitespace, and want to strip it out. Open google and search for “vim remove trailing whitespace” and use some regular expression in a search and replace command. But this can be automated easily.</p>
<p>Instead of having to remember this command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:%s/\s\+$//e
</code></pre></div></div>
<p>I make a command that will do it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>command Trim %s/\s\+$//e
</code></pre></div></div>
<p>Now I just have to remember the command, and <code class="highlighter-rouge">Trim</code> is much easier for me to remember.</p>
<p>Or get make a function that I can call from other vim script:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function! Trim()
%s/\s\+$//e
endfunction
</code></pre></div></div>
<p>It just keeps building on the same commands. And really, what could go wrong?</p>
<p>If you want to learn more, I highly recomend Steve Losh’s <a href="http://learnvimscriptthehardway.stevelosh.com/">Learn Vimscript the Hard Way</a>. I also have a more robust version of the <a href="https://github.com/csexton/trailertrash.vim">trim command</a>.</p>
Navigating the Command Line2012-01-13T00:00:00+00:00http://www.codeography.com/2012/01/13/navigating-the-command-line<p>When learning to love the command line, nothing made a bigger difference to me than when I discovered I could edit commands with out pressing and holding the arrow keys. That was just slow and awkward. There is a better way. Really you only need two or three little tricks and you will be in a whole new world of productivity.</p>
<p>If you can only learn one thing, learn these two keyboard shortcuts:</p>
<style>
.key-image { margin-top: 10px; height: 60px; }
table.keys { vertical-align:top; }
table.keys h2 { margin-bottom: 0; }
table.keys, td, th { vertical-align: top; }
table.keys td.col1 { width:141px; }
</style>
<table class="keys">
<tr>
<td class="col1"><img src="/images/c-a.png" align="left" class="key-image" /></td>
<td class="col2">
<h2>Jump to the beginning</h2>
Pressing <code>control-a</code> will jump the cursor to the beginning of the line.
<br />
Mnemonic: Control-<em>Awesome</em> I can move back to the beginning with out holding the arrow key.
<br />
Also I find I remember this because the A key is the furthest left key on the home row.
</td>
</tr>
<tr>
<td class="col1"><img src="/images/c-e.png" align="left" class="key-image" /></td>
<td class="col2">
<h2>Jump to the end</h2>
Pressing <code>control-e</code> will jump the cursor to the end of the line.
<br />
Mnemonic: Control-<em>End</em>
</td>
</tr>
</table>
<p>Now, take a few minutes to go give those a try. I’ll wait.</p>
<p>Want some more? Rad. But a little caution if you are just learning these things: just pick a couple and find ways to use them until they are second nature. Practice. If you think you are ready for more, here you go. I think these are the next most useful:</p>
<table class="keys">
<tr>
<td class="col1"><img src="/images/c-w.png" align="left" class="key-image" /></td>
<td class="col2">
<h2>Delete Back a Word</h2>
Pressing <code>control-w</code> will delete the word before the cursor.
<br />
Mnemonic: Control-<em>W</em>hy did I type that <em>Word</em>
</td>
</tr>
<tr>
<td class="col1"><img src="/images/c-k.png" align="left" class="key-image" /></td>
<td class="col2">
<h2>Delete to the End</h2>
Pressing <code>control-k</code> will delete from the cursor to the end of the line
<br />
Mnemonic: Control-<em>Kill</em> to the end of the line
</td>
</tr>
<tr>
<td><img src="/images/c-u.png" align="left" class="key-image" /></td>
<td>
<h2>Delete to the Beginning</h2>
Pressing <code>control-u</code> will delete from the cursor to the beginning of the line
<br />
Mnemonic: Control-<em>Uhh</em> that wasn't right
</td>
</tr>
</table>
<p>I think these are the most critical shortcuts to learn, and have made life on the command line damn nice.</p>
<h2 id="a-bit-about-input-modes">A Bit About Input Modes</h2>
<p>Really I should end this post here, but am somehow compelled to mention this thing called input modes.</p>
<p>There are two input modes that a command line will use: vi or emacs.</p>
<p>The examples above assume you are using emacs mode for your shell. This is the default for bash and most other shells. If you are having problems with them you may need to set the input mode. In bash you can simply run <code class="highlighter-rouge">set -o emacs</code></p>
<p>I can hear you asking “But wait, you are a vim guy, why do you use emacs mode for your shell?”</p>
<p>Well, it wasn’t an easy choice. I thought I would like vi mode on the command line. And I tried to use it. I wanted to want to. But in the end it was just never felt right.</p>
<p>My reasons:</p>
<ol>
<li>It is the default on most systems. Nice to open a new term on a strange server and have things Just Work™.</li>
<li>Anywhere libreadline is used these things will work. Basically this is the line editing library that most terminal based apps will use. This includes your shell, bash, irb, ipython, irc clients and the like.</li>
<li>I use a Mac, and there is a decent overlap between the default keyboard shortcuts in Cocoa and emacs mode.</li>
<li>On the command line I can quickly edit the command in vim by mashing <code class="highlighter-rouge">Control-X Control-E</code> or running <code class="highlighter-rouge">fc</code>.</li>
<li>And probably the most critical reason is I have the <a href="https://github.com/csexton/viceroy/blob/master/plugin/mappings.vim#L14">exact same keybindings</a> in Vim’s insert and command modes.</li>
</ol>
<h2 id="ignore-advice-from-blog-articles">Ignore Advice from Blog Articles</h2>
<p>The only thing you should do is pick some tools and learn them. Don’t worry about what some random blog article says. Don’t worry about those kids on irc demanding you use zsh. Don’t worry about editors – learn something. It will all translate in some way, won’t be wasted effort. Most important thing you can do as a developer is train how to use your tools.</p>
<h2 id="what-do-you-use">What do you use?</h2>
<p>What command line tricks do you use to make your day happier?</p>
Making ARC and non-ARC files play nice together2011-10-10T00:00:00+00:00http://www.codeography.com/2011/10/10/making-arc-and-non-arc-play-nice<p>If you want to exclude a file from being compiled with ARC you can do so by setting a flag on the .m file:</p>
<p>Click the Project -> Build Phases Tab -> Compile Sources Section -> Double Click on the file name</p>
<p>Then add <code class="highlighter-rouge">-fno-objc-arc</code> to the popup window.</p>
<p>Likewise, if you want to include a file in ARC, you can use the <code class="highlighter-rouge">-fobjc-arc</code> flag.</p>
<p><img alt="Xcode Screen Shot" src="/images/arc-compiler-flag.png" style="width: 100%;" /></p>
<p>See the <a href="http://clang.llvm.org/docs/AutomaticReferenceCounting.html">clang docs</a> for more details.</p>
<p>A helpful trick is to use the <code class="highlighter-rouge">__has_feature</code> language extension to throw errors when this is not set properly.</p>
<p>Enforce a file is ARC:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#if ! __has_feature(objc_arc)
#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag
#endif
</code></pre></div></div>
<p>The inverse:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#if __has_feature(objc_arc)
#error This file cannot be compiled with ARC. Either turn off ARC for the project or use -fno-objc-arc flag
#endif
</code></pre></div></div>
<p>This was adapted from a <a href="http://lists.apple.com/archives/objc-language/2011/Aug/msg00036.html">post by Greg Parker</a> on the on the Objective-C mailing list. He goes on to point out the following:</p>
<p>You should be careful with the interface to your shared code such that ARC and non-ARC clients can use it freely.</p>
<ul>
<li>Conform to Cocoa’s memory management conventions even though an all-ARC or no-ARC project would not require it</li>
<li>Don’t use object pointers inside C structs</li>
<li>Avoid CF types</li>
</ul>
Prevent Xcode from opening extra projects2011-10-05T00:00:00+00:00http://www.codeography.com/2011/10/05/prevent-xcode-from-opening-extra-projects<p>Insistent I don’t want persistence.</p>
<p>I’ve been a little annoyed with Xcode on Lion. Every time I open a project it also opens the last project I was working on. This might be fine if I was only working on one project – but recently I have been working on Captured in the evenings, and Zippy’s iPhone app during the day. I don’t want to open the project for Captured when I get to work in the morning. Plus it is particularly frustrating when one of those projects is a workspace, if you create a new project Xcode insists on adding it to the current workspace.</p>
<p>The solution: fix my <code class="highlighter-rouge">xcode</code> script, by passing in a user defaults flag.</p>
<p>I have been using a helper function to load xcode from the command line for a while now, and really it is the primary way that I open a project. Maybe I am in minority for Cocoa developers, but I live on the command line – so this is better for me.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env ruby</span>
<span class="n">f</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">f</span><span class="p">.</span><span class="nf">concat</span> <span class="no">Dir</span><span class="p">[</span><span class="s2">"*.xcworkspace"</span><span class="p">]</span>
<span class="n">f</span><span class="p">.</span><span class="nf">concat</span> <span class="no">Dir</span><span class="p">[</span><span class="s2">"*.xcodeproj"</span><span class="p">]</span>
<span class="k">if</span> <span class="n">f</span><span class="p">.</span><span class="nf">length</span> <span class="o">></span> <span class="mi">0</span>
<span class="nb">puts</span> <span class="s2">"opening </span><span class="si">#{</span><span class="n">f</span><span class="p">.</span><span class="nf">first</span><span class="si">}</span><span class="s2">"</span>
<span class="sb">`open -a /Developer/Applications/Xcode.app </span><span class="si">#{</span><span class="n">f</span><span class="p">.</span><span class="nf">first</span><span class="si">}</span><span class="sb"> --args -ApplePersistenceIgnoreState YES`</span>
<span class="nb">exit</span> <span class="mi">0</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"No Xcode projects found"</span>
<span class="nb">exit</span> <span class="mi">1</span>
</code></pre></div></div>
<p>The trick is the <code class="highlighter-rouge">ApplePersistenceIgnoreState</code> option passed in to Xcode, this overrides the NSUserDefault for the app persistence.</p>
<p>If you want to use this, just create a file <code class="highlighter-rouge">xcode</code> somewhere in your path and then set it to be executable <code class="highlighter-rouge">chmod +x xcode</code>. Then opening project is as simple as:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd path/to/proj
xcode
</code></pre></div></div>
<p>Refreshing.</p>
Project specific git author, without the gas pains2011-08-05T00:00:00+00:00http://www.codeography.com/2011/08/05/project-specific-git-author<p>I heard about a git-related project called GAS, the <a href="https://github.com/walle/gas">Git Author Switcher</a>, on that <a href="http://ruby5.envylabs.com/">Ruby5</a> podcast–and initially I was intrigued. But once I thought about it, I think there is a better way to handle this. With just plain ole git.</p>
<p>Why don’t I like having GAS? Well, it changes the author globally – and you have to remember to switch it up when changing projects. I would prefer to set it on a per project basis, then forget about it.</p>
<p>So my setup is to put my personal user and email (i.e. the one I use on github) in the global config, which most anyone using git should have setup already:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global user.name "Chris"
git config --global user.email "chris@personal.dev"
</code></pre></div></div>
<p>Then in my work projects, I use a different email address, so I change it in that repo by running:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config user.email "chris@work.dev"
</code></pre></div></div>
<p>Luckily, I don’t use a different name at work, so there is no need to override that setting. Although I could if I really wanted to.</p>
<p>If you have to to this frequently, I think a simple git alias is pretty nice for streamlining this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global alias.workprofile 'config user.email "chris@work.dev"'
</code></pre></div></div>
<p>Then when you clone a new work project, just run <code class="highlighter-rouge">git workprofile</code> and it will be configured to use that email.</p>
<p>Admittedly, if you are using a shared machine or are pairing (or pairing on a shared machine), then GAS might be exactly what you need. Just use the right tool for the job.</p>
Multiple Dropboxen on Mac the right way2011-07-07T00:00:00+00:00http://www.codeography.com/2011/07/07/multiple-dropboxen-on-mac<p>I really didn’t like the way other people explained setting up multiple dropboxen on a mac, which involved creating multiple directories and files, incliuding, of all things, faux app bundles. This bugged me, so I made a new launchd.plist and drive it all from that one config file.</p>
<p>First, create a file in <code class="highlighter-rouge">~/Library/LaunchAgents/com.dropbox.alt.plist</code> with the following contents, updating the USERNAME for your username.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="cp"><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"></span>
<span class="nt"><plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>Label<span class="nt"></key></span>
<span class="nt"><string></span>com.dropbox.alt<span class="nt"></string></span>
<span class="nt"><key></span>LowPriorityIO<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"><key></span>EnvironmentVariables<span class="nt"></key></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>HOME<span class="nt"></key></span>
<span class="nt"><string></span>/Users/USERNAME/.dropbox-alt<span class="nt"></string></span>
<span class="nt"></dict></span>
<span class="nt"><key></span>ProgramArguments<span class="nt"></key></span>
<span class="nt"><array></span>
<span class="nt"><string></span>/Applications/Dropbox.app/Contents/MacOS/Dropbox<span class="nt"></string></span>
<span class="nt"></array></span>
<span class="nt"><key></span>RunAtLoad<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"></dict></span>
<span class="nt"></plist></span>
</code></pre></div></div>
<p>Second, run the following commands:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>launchctl load ~/Library/LaunchAgents/com.dropbox.alt.plist
launchctl start com.dropbox.alt
</code></pre></div></div>
<p>The Dropbox dialog will appear. On the “Setup Type” screen of their installer make sure you change the folder to a custom location that makes sense for you (otherwise it will put it in ~/.dropbox-alt/Dropbox).</p>
<p><img src="/images/dropbox01.png" alt="Dropbox Installer" /></p>
<p>Done. No faux app bundles. Everything is controled by launchd, just the way it should be.</p>
Dynamic fixed width layout with CSS2011-06-14T00:00:00+00:00http://www.codeography.com/2011/06/14/dynamic-fixed-width-layout-with-css<p><img align="right" src="/images/dynamic-layout-sm.png" alt="iPhone and iPad" /></p>
<p>Recently <a href="http://cary.blog.greenfrylabs.com/">Cary</a> and I have been trying to optimize our site for different devices and ran in to some issues. Particularly if we wanted to have a site that would work well on an iPhone it was comically large on the iPad. And the awesome iPad version was teeny-tiny on the phone. With more digging into the viewport meta tags there was no good way to select a tablet layout vs. a phone layout – you just have the one viewport and that’s it. The only decent way to determine which device you have is to set the viewport’s width to be <code class="highlighter-rouge">device-width</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><meta name="viewport" content="width=device-width" />
</code></pre></div></div>
<p>But if you do that you are stuck at the native widths for the devices. You have the default 320px for portrait iPhone or 1024px for landscape iPad, and a number of other variations.</p>
<p>That all well and good if you want to design specifically for those viewport sizes – but if you want to set a custom viewport for the phone and for a tablet, which is what we wanted, then a little more trickery is involved. But the end result was really very slick and, stay with me here, maintainable.</p>
<p>Something I was calling “Dynamic, stepwise, fixed-with layout.”</p>
<p>To pull this off you need to things:</p>
<h3 id="set-the-viewport-for-your-device">Set the viewport for your device</h3>
<p>Update the viewport via javascript in the <code class="highlighter-rouge">head</code> of the HTML:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><meta name="viewport" content="width=device-width" />
<script type="text/javascript">
if (window.innerWidth < 500) {
// Phone
document.querySelector("meta[name=viewport]").setAttribute('content', 'width=480');
}
else if (window.innerWidth < 650) {
// Tablet
document.querySelector("meta[name=viewport]").setAttribute('content', 'width=670');
}
</script>
</code></pre></div></div>
<p>This has the viewport default to <code class="highlighter-rouge">device-width</code> which lets us grab the size of the window, and set it to our custom size.</p>
<p>I put this JS directly in the header, and have it evaluate immediatly because I don’t want the screen to ‘jump’ around after it loads.</p>
<h3 id="add-custom-styles-for-that-viewport">Add custom styles for that viewport</h3>
<p>Once I have that new viewport size I can use CSS media queries to style the page for the devices.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@media screen and (max-width: 500px) {
/* Phone Styles */
}
@media screen and (max-width: 700px) {
/* Tablet Styles */
}
</code></pre></div></div>
<p>The really cool thing about this approach is you can dynamically set the width of your content to an arbitrary value based on the device size.</p>
<p>Added bonus, as you resize the browser window on your computer you will also get the custom layouts. Which is particularly nice for testing.</p>
<p>Check out the <a href="#" onclick="window.open('/examples/dynamic-layout.html','linkname','height=480, width=502,scrollbars=no')">Example</a>.</p>
Zsh trick: restart pow with command completion2011-05-10T00:00:00+00:00http://www.codeography.com/2011/05/10/zsh-trick-restart-pow-with-command-completion<p>Recently I started using the zero configuraiton web server <a href="http://pow.cx/">pow</a> from the good folks at 37signals and absolutly love it. I really like how restarting the server is as simple as touching <code class="highlighter-rouge">restart.txt</code> to the <code class="highlighter-rouge">tmp</code> directory. However I have been working on a feature that requires frequent restarts of the server and found it repetitive. Since I was being lazy about typing in the path to <code class="highlighter-rouge">restart.txt</code> I decided to automate it a little. And add command completion.</p>
<p>Got those with the following zsh script:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kapow(){
touch ~/.pow/$1/tmp/restart.txt;
if [ $? -eq 0 ]; then; echo "pow: restarting $1" ; fi
}
compctl -W ~/.pow -/ kapow
</code></pre></div></div>
<p>This gives me a <code class="highlighter-rouge">kapow</code> command that will restart the app for me.</p>
<p>I also put it up in a <a href="https://gist.github.com/965032">gist</a>, if you would like to fork it and make changes.</p>
Quickly navigate your projects in zsh, with tab completion2011-05-01T00:00:00+00:00http://www.codeography.com/2011/05/01/quickly-navigate-your-projects-in-zsh-with-tab-completion<p>I find my self having to frequently jump between projects in the terminal, or opening new tabs in Terminal and needing to navigate to the project I am working on. I know there are some other tricks for doing this, some of the optimized for certain cases (like a new tab in the current directory), but I found this to be the most useful for how I work.</p>
<p>Since I keep all my projects in a directory called <code class="highlighter-rouge">~/src</code> I created a function called <code class="highlighter-rouge">src</code> that would get me there quickly, so instead of this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd ~/src/my-web-site
</code></pre></div></div>
<p>I can do this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ src my-seb-site
</code></pre></div></div>
<p>Well, that’s nice and all, but with out tab completion I would never use it. Turns out that is stupid simple to solve with zsh’s rad completion system. My final solution looks something like this.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>src(){cd ~/src/$1;}
compctl -W ~/src -/ src
</code></pre></div></div>
<p>Just drop that into your <code class="highlighter-rouge">~/.zshrc</code> file and you should be good to go. Feel free to replace <code class="highlighter-rouge">src</code> with what ever you name your projects directory (Projects, source, awesome-stuff).</p>
<p>If you have not enabled zsh’s completion somewhere else in your configs, you may need to add the following before the compctl call:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>autoload -U compinit
compinit -i
</code></pre></div></div>
<p>Of course, if that’s the case, I recommend installing <a href="https://github.com/robbyrussell/oh-my-zsh">Oh My Zsh</a> and getting all sorts of goodness.</p>
Keeping track of deploys: Make an about.txt with Capistrano2011-04-27T00:00:00+00:00http://www.codeography.com/2011/04/27/keeping-track-of-deploys-make-an-about.txt-with-capistrano<p>I wrote this for an app couple years ago and needed it agian – so I went and dug it up. I am certinan could be done in a more elegent way, but this works well and gives the information I needed about each deploy. Plus I know that both PM and QA folks understand how this works with very minimal guidence. Makes triaging issues go much smoother.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>namespace :deploy do
desc "Create about and revision files."
task :after_update_code, :roles => :app do
run "echo \"Version Info\" > #{release_path}/public/about.txt"
run "echo \"============\" >> #{release_path}/public/about.txt"
run "echo \"Version: `cat #{release_path}/VERSION`\" >> #{release_path}/public/about.txt"
run "echo \"Deploy Date: `date`\" >> #{release_path}/public/about.txt"
run "cd #{release_path} && echo \"Ref: `git rev-parse --short HEAD`\" >> #{release_path}/public/about.txt"
run "echo \"Branch: #{revision}\" >> #{release_path}/public/about.txt"
run "echo \"Installer Info: see /download/about.txt\" >> #{release_path}/public/about.txt"
run "echo \"#{revision}\" > #{release_path}/public/revision.txt"
end
end
</code></pre></div></div>
<p>You can find the gist up on <a href="https://gist.github.com/941035">github</a>.</p>
Basics of RubyGems Slides2011-04-01T00:00:00+00:00http://www.codeography.com/2011/04/01/basics-of-rubygems-slides<p>My slides from RubyNation are now up on <a href="http://basicsofrubygems.heroku.com">heroku</a> and the examples are on <a href="http://github.com/csexton">github</a>.</p>
Define Your Inner Foo2011-03-11T00:00:00+00:00http://www.codeography.com/2011/03/11/define-your-inner-foo<p>Recently attended a great talk by <a href="http://paulbarry.com/">Paul Barry</a> at the <a href="http://www.meetup.com/dcruby/">DCRUG</a>. During his talk, he wondered off into defining a method in a method.</p>
<p>This was really cool.</p>
<p>I took some time playing with this, and after showing a few colleagues, I had to write this up. I encourage you to fire up IRB and try it your self. This is probably not something you would actually want to do in a project, but once you know about it then you will be tempted to find a problem for this solution.</p>
<p>define_your_inner_foo.rb:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class DefineYourInnerFoo
def foo
def foo
def foo
"Zirbert"
end
"Zaz"
end
"Zing"
end
end
</code></pre></div></div>
<p>irb:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>> load 'define_your_inner_foo.rb'
>> f = DefineYourInnerFoo.new
>> f.foo #=> 'Zing'
>> f.foo #=> 'Zaz'
>> f.foo #=> 'Zirbert'
>> f.foo #=> 'Zirbert'
>> g = DefineYourInnerFoo.new
>> g.foo #=> 'Zirbert'
>> g.foo #=> 'Zirbert'
</code></pre></div></div>
<p>A slightly more contrived example:</p>
<p>animal.rb:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Animal
def speak
"Hello, I am a Animal"
end
def be_dog
def speak
"Woof"
end
end
def be_bird
def speak
"Tweet-a-leet"
end
end
def be_whale
def speak
"HeeeeeeiiilllllllloooooooooOOOOOOooo....oooooOOOOoo"
end
end
end
</code></pre></div></div>
<p>irb:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>> load 'animal.rb' #=> true
>> a = Animal.new #=> #<Animal:0x00000101126900>
>> a.speak #=> "Hello, I am a Animal"
>> a.be_dog #=> nil
>> a.speak #=> "Woof"
>> a.be_bird #=> nil
>> a.speak #=> "Tweet-a-leet"
>> b = Animal.new #=> #<Animal:0x000001010eeeb0>
>> b.speak #=> "Tweet-a-leet"
>> b.be_whale #=> nil
>> a.speak #=> "HeeeeeeiiilllllllloooooooooOOOOOOooo....oooooOOOOoo"
</code></pre></div></div>
Focus on a test in Vim2011-02-14T00:00:00+00:00http://www.codeography.com/2011/02/14/focus-on-a-test-in-vim<p>I have found myself in the situation where I would have Vim running in one window, and a terminal open on the other monitor with my tests. And noticed I was constantly dancing across the keyboard <code class="highlighter-rouge">⌘-tab;⌃-p;↩;⌘-tab</code> (switch windows to Terminal; previous command; enter; switch windows to Vim). Of course this muscle memory was broken when I switched to my browser in between. I wanted to automate this.</p>
<p>I could use autotest, but our test suite is slow to start up and I wanted to focus on one test.</p>
<p>I could run that test within Vim, but MacVim does not show the color escapes when running a command, plus it blocks my editing while I wait for the tests to run.</p>
<p>I could use Vim in the terminal, but I like my ⌘ key mappings and colors.</p>
<p>My solution:</p>
<ol>
<li>Run the command from Vim in the background and redirect the output to a file</li>
<li>Tail the log in Terminal</li>
</ol>
<p>How to do it:</p>
<p>Run your test in Vim, the line I would use is something like this (just replace the command bit with the one you want to run):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>map <D-r> :silent execute "!ruby test/unit/post_test.rb &> /tmp/vim.log &" <cr>
</code></pre></div></div>
<p>And tail the logs:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ tail -f /tmp/vim.log
</code></pre></div></div>
<p>Now when ever I press <code class="highlighter-rouge">⌘-r</code> I can keep on tinkering with the code while the tests run on the other monitor.</p>
<p>I don’t keep that command in my <code class="highlighter-rouge">.vimrc</code> file because I am constantly going back and changing the command – this has become a macro that I change around as I am focusing on different parts of my code.</p>
<p>Protip: use <code class="highlighter-rouge">q:</code> to interactively edit and run past Vim commands.</p>
<p>Beauty of this is it works on any command, in any language I am programming in.</p>
Deploying from your current branch with Capistrano2010-12-09T00:00:00+00:00http://www.codeography.com/2010/12/09/deploying-from-your-current-branch-with-capistrano<p>In some of the Rails projects I have worked on, I have found my self having to juggle multiple environments and often want to shuffle around which branch is deployed to which environment. I use Capistrano Multistage to handle all the different environments, but didn’t want to have to edit the deploy configuration every time I wanted to deploy. So I came up with a way to deploy from whatever my current local branch. Assuming this branch is on the remote git server, Capistrano would deploy from there.</p>
<p>In your <code class="highlighter-rouge">config/deploy.rb</code> file, add</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Bonus! Colors are pretty!
def red(str)
"\e[31m#{str}\e[0m"
end
# Figure out the name of the current local branch
def current_git_branch
branch = `git symbolic-ref HEAD 2> /dev/null`.strip.gsub(/^refs\/heads\//, '')
puts "Deploying branch #{red branch}"
branch
end
# Set the deploy branch to the current branch
set :branch, current_git_branch
</code></pre></div></div>
<p>The really cool thing about this is how intuitive it is to use. Goes something like this:</p>
<p>PM: Hey, can you deploy feature-x to staging! NOW!
Me: K, <code class="highlighter-rouge">git checkout feature-x && cap deploy staging</code></p>
<p>That just feels natural.</p>
<p>On other alternative was to setup a remote branch in git that matches each environment, and go a <code class="highlighter-rouge">git reset --hard</code> when you want to change things around. But with as often as we were redeploying that seemed burdensome.</p>
Most important configuration on a Mac2010-12-02T00:00:00+00:00http://www.codeography.com/2010/12/02/remap-capslock-to-control-on-a-mac<p>One of the most important things you can do on a mac is remap caps lock to control. Sure, I am a little over zealous about this topic, but I really feel that this can make a huge diffrence to people who use modifier keys alot. And if you use a Mac properly one of the first things you should set out to learn are the keyboard shortcuts to perform you commmon tasks.</p>
<p><img src="/media/remap-caps-1.png" alt="System Prefrences" /></p>
<p>Open system prefrences and click on Keyboard.</p>
<p><img src="/media/remap-caps-2.png" alt="Keyboard Prefrences" /></p>
<p>Click on the ‘Modifier Keys’ button.</p>
<p><img src="/media/remap-caps-3.png" alt="Modifier Key Settings" /></p>
<p>On the first dropdown, the one for Caps Lock</p>
<p><img src="/media/remap-caps-4.png" alt="Modifier Options Dropdown" /></p>
<p>Set it to be Control.</p>
<p>Why am I so over enthusiastic about this? Mostly because I use to get wrist pain in my left hand and nosiced I was straining to contort my hand to press common keys like <Control>-A, which is got to beginning of line on OS-X (and in emacs/terminal/anywhere awesome). Suddenly this became easy and quick. Way better faster and easier on my wrist.</p>
<p>Added bonus (as if I could pick just one added bonus): Launch Bar uses <Control>-J and <Control>-K to act as up and down. This alone is one producitivity hack that speeds up many common tasks for me.</p>
<p>Give it a shot, make is muscle memory and you won’t want to go back.</p>
Conditionally Colorful Test Unit2010-11-02T00:00:00+00:00http://www.codeography.com/2010/11/02/conditionally-colorful-test-unit<p>I like to use the redgreen gem to make my tests colorful, but hardly want to make this a hard requirement to work with the project, so I tend to add this one-liner to the top of test_helper.rb – now I get red and green output but the other guys on the team don’t have to deal with installing the gem.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>begin; require 'redgreen'; rescue Exception=>e;end
</code></pre></div></div>
Zip for Distribution: The missing build step in Xcode2010-09-25T00:00:00+00:00http://www.codeography.com/2010/09/25/the-missing-build-step-in-xcode<p>I have worked on a couple teams that have submitted iPhone Apps to the iTunes store, however I had never gone through the process on my own until this week. Well, turns out you need to use Apple’s “Application Loader.app” to submit your app. So I fired it up, and was unable to select my .app bundle. This confused me, and the documentation probably mentions how to do this, but I just took a swing in the dark and zipped the file. This worked.</p>
<p>While right clicking on the file and selecting “compress” is pretty easy, I also had to rename my file to remove any spaces. Well this has become too many steps for any self respecting programmer. My solution is a custom post build phase:</p>
<p><img src="/images/xcode-add-custom-build-phase.png" alt="Custom Build Phase Screenshot" /></p>
<p>Then I add the following script (making sure the <code class="highlighter-rouge">shell</code> is set to /bin/sh):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># We only want to build the zip file when we build for distribution
if [ "$CONFIGURATION" = "Distribution" ]
then
# Create a short name with no spaces and remove the ".app" from the end
SHORT_NAME=`echo "$EXECUTABLE_FOLDER_PATH" | sed 's/ //g' | sed 's/\.app$//g'`
# Zip the file
zip -u -1 "$TARGET_BUILD_DIR/$SHORT_NAME.zip" "$TARGET_BUILD_DIR/$EXECUTABLE_FOLDER_PATH"
# Tell us what happened
echo "Built distribution zip file: $TARGET_BUILD_DIR/$SHORT_NAME.zip"
fi
</code></pre></div></div>
<p>At this point I like to right click on the build step and rename it to something useful, something like “Zip App Bundle for Distribution”, but hey, that’s me.</p>
How to make Vim a first class CSS editor2010-08-02T00:00:00+00:00http://www.codeography.com/2010/08/02/how-to-make-vim-a-first-class-css-editor<p>I have always struggled with CSS in vim. Seems like it would be easy to implement compared to auto-complete in other filetypes.</p>
<p>All I really wanted to have was some sort of reminder on what was valid properties and where to put the positional arguments when I am using the shorthand properties.</p>
<p>Today I discovered the two things I needed to fix this. SnipMate and Omnicomplete</p>
<h2 id="snipmate">SnipMate</h2>
<p>I forked the basic SnipMate and added some simple snippets for CSS. If you want to use it, then you can install from my GitHub repo directly</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone git://github.com/csexton/snipmate.vim.git
cd snipmate.vim
cp -R * ~/.vim
</code></pre></div></div>
<p>Or you can just grab the <a href="http://github.com/csexton/snipmate.vim/blob/master/snippets/css.snippets">css.snippets</a> file and add it to your .vim/snippets directly.</p>
<h2 id="omnicomplete">Omnicomplete</h2>
<p>This is built in to Vim 7, I just didn’t realize it worked for CSS. a simple <code class="highlighter-rouge">crtl-x ctrl-o</code> and it should attempt to complete your word for you. Cool thing is that if you use it after a property before you even start to type you can invoke it to get a list of properties.</p>
<p>If this does not work, should make sure that the omnifunc it set to use the CSS completer:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:set omnifunc=csscomplete#CompleteCSS
</code></pre></div></div>
<h2 id="making-the-css-dance">Making the CSS Dance</h2>
<p>Now that you have both of those installed you can do cool stuff like complete your property values</p>
<p><img src="/images/vim-css-prop-value.png" alt="Vim CSS Property Value" /></p>
<p>After typing “border-style: “ I pressed type <code class="highlighter-rouge">ctrl-x ctrl-o</code> and get a handy popup complete list.</p>
<p><img src="/images/vim-css-snip.png" alt="Vim CSS Snipet" /></p>
<p>This was generated by typing “margin:<tab>”. No longer have to go look up which order the parameters go in.</p>
<h2 id="sassy-update">Sassy Update</h2>
<p>To get this trickery to work with scss files, add the following to your vimrc:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>autocmd BufNewFile,BufRead *.scss set ft=scss.css
</code></pre></div></div>
PackageMaker could not copy unreadable files2010-07-28T00:00:00+00:00http://www.codeography.com/2010/07/28/packagemaker-could-not-copy-unreadable-files<p>I was getting a bizarre error with Apple’s PackageMaker</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% /Developer/usr/bin/packagemaker --filter "\.DS_Store" --root-volume-only --domain system --verbose --no-relocate -l "/" --target 10.5 --id com.codeography.program.pkg --resources build/Release/Package/resources --scripts build/Release/Package/scripts --title "Program Name 2.1.10" --version 2.1.10 --root build/Release/Package/root --out installer.pkg
Preverifying root
Preverifying root
Checking bundle identifiers
Checking package configuration
Checking contents
Loading contents
Applying Recommended Permissions
Checking for ZeroLink
Preverifying Program Name 2.1.10
Preverifying Program Name 2.1.10
Building root
Building root
Copying Scripts
Copying unreadable files to temporary location
ERROR: Could not copy unreadable files.
Renaming package files
</code></pre></div></div>
<p>After hours of searching I found that I had a vim swap file that wasn’t world readable. And when I change the owner of the files that I need to package to be root, my user no longer had read permissions. Finding this was pretty easy using the <code class="highlighter-rouge">find</code> command.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% find . \! -perm -444
installer/config/.Info.plist.swp
</code></pre></div></div>
<p>Deleted that file and everything worked.</p>
Don't need no json.vim, get json syntax highlighting for free2010-07-13T00:00:00+00:00http://www.codeography.com/2010/07/13/json-syntax-highlighting-in-vim<p>Recently I needed to work with some .json files and notice vim didn’t know how to highlight them. A little baffled I turned to google and discovered json.vim. Installed it, setup the autocommand to reconize .json files as json and was set.</p>
<p>But being stingy about what plugins I load, it dawned on me – vim supports JavaScript, why not just use that for highlighting my json files? doing so was stupid-easy. Just add this line to your .vimrc:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>autocmd BufNewFile,BufRead *.json set ft=javascript
</code></pre></div></div>
<p>Done and done. Got good-enough hihglighting and only added one line of vimscript.</p>
rvm and vim combined: tastes like awesome2010-06-25T00:00:00+00:00http://www.codeography.com/2010/06/25/rvm-and-vim-tastes-like-awesome<p>After a <a href="http://twitter.com/bryanl/status/17013225815">tweet</a> about vim status lines by non other than <a href="http://smartic.us/">Bryan Lyles</a> I set out to get git and rvm info in vim’s status line. Well, git was easy since I was using Tim Pope’s fugitive plugin:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>set statusline+=%{fugitive#statusline()}
</code></pre></div></div>
<p>But had no such luck with rvm, so I decided to roll my own. And thus we have <a href="http://github.com/csexton/rvm.vim">rvm.vim</a>. Which will report the ruby interperter you are using, the version of that guy and the active gemset (if you have one). It does assume you start vim from the terminal, but what self respecting vim user dosen’t live on the command line all day long?</p>
<p>Installation is easy, just go back to the aforementioned command line and paste this in:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl http://github.com/csexton/rvm.vim/raw/master/plugin/rvm.vim > ~/.vim/plugin/rvm.vim
</code></pre></div></div>
<p>Or if you are one of the cool kids and use <a href="http://github.com/tpope/vim-pathogen">pathogen</a> you can just clone the repo into your bundle directory:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone http://github.com/csexton/rvm.vim.git ~/.vim/bundle
</code></pre></div></div>
<p>And this will give you a similar status line trick to fugitive:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>set statusline+=%{rvm#statusline()}
</code></pre></div></div>
<p>What good is this hotness with out a screen shot?</p>
<p><img src="/images/vimrvm.png" alt="rvm statusline" /></p>
<p>If you want your status line to look just like this, this is how to do it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>set statusline=[%n]\ %<%.99f\ %h%w%m%r%y%{exists('g:loaded_fugitive')?fugitive#statusline():''}%{exists('g:loaded_rvm')?rvm#statusline():''}%=%-16(\ %l,%c-%v\ %)%P
</code></pre></div></div>
<p>What’s on your vim status line?</p>
Exclude bundler gems from Heroku deployment2010-05-20T00:00:00+00:00http://www.codeography.com/2010/05/20/exclude-bundler-gems-from-heroku-deployment<p>I had some gems that I only needed for development on my mac, and did not want them to be installed to my Heroku slug. I didn’t want them installed because they would break the deployment.</p>
<p>Everything was fine until I wanted to use autotest with my Rails 3 app that is hosted on Heroku. I got this error when I tried to deploy:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ERROR: Failed to build gem native extension. (Gem::Installer::ExtensionBuildError)
/usr/ruby1.9.1/bin/ruby extconf.rb
extconf.rb:19:in `<main>': Only Darwin (Mac OS X) systems are supported (RuntimeError)
Gem files will remain installed in /disk1/tmp/12479_23567910067960/.bundle/gems/gems/autotest-fsevent-0.2.2 for inspection.
</code></pre></div></div>
<p>As they call out in their <a href="http://docs.heroku.com/bundler">documentation</a>, “Heroku does not specify any groups during bundle installation, so all gems from all groups will be bundled with your application.” I needed to find a way to exclude some libraries from being installed.</p>
<p>Based on a tip from the Heroku <a href="http://groups.google.com/group/heroku/browse_frm/thread/2a533b210b400e69/c9d753e89758ed57?hl=en&lnk=gst&">mailing list</a> I found that the following worked:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem "autotest-fsevent" if RUBY_PLATFORM =~ /darwin/
</code></pre></div></div>
<p>But if I was going to exclude one gem, I figured I could exclude all my development gems, so I wound up doing this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if RUBY_PLATFORM =~ /darwin/
group :test do
gem "rspec-rails", ">= 2.0.0.beta.8"
gem 'factory_girl', :git => 'git://github.com/thoughtbot/factory_girl.git', :branch => 'rails3'
gem 'autotest-rails'
gem 'autotest'
gem 'autotest-fsevent'
gem 'autotest-growl'
end
end
</code></pre></div></div>
<p>So I made that change, and deployment was still failing. I removed my Gemfile.lock and everything worked.</p>
<p>This presents a complication, which according to <a href="http://yehudakatz.com/2010/04/">Yehuda</a>, “because gems no longer live in your application, we needed a way to snapshot the list of all versions of all gems used at a particular time, to ensure consistent versions across machines and across deployments.”</p>
<p>To work around this I am specifying exact versions of the gems in my Gemfile.</p>
<p>Of course if Heroku added support for <code class="highlighter-rouge">bundle install --without test</code>, everything would <em>work just as it should</em>™.</p>
<p>Added Bonus: My compiled slug size went from 19.6MB to 5.1MB.</p>
Truncating strings in css2010-05-19T00:00:00+00:00http://www.codeography.com/2010/05/19/truncating-strings-in-css<p>Filed under “Stupid CSS Tricks”</p>
<p>I had no idea you could insert an ellipises into html with css, and combined with overflow and white-space directives you can very politely clip a string.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>row_title {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
</code></pre></div></div>
<p>So instead of this:</p>
<div style="margin: 1em;width:30em; border:thin dotted red; overflow: hidden; white-space: nowrap;">
I saw the best minds of my generation Destroyed by madness, starving, hysterical
</div>
<p>Or this:</p>
<div style="margin: 1em;width:30em; border:thin dotted red; white-space: nowrap;">
I saw the best minds of my generation Destroyed by madness, starving, hysterical
</div>
<p>You get this sexxy beast:</p>
<div style="margin: 1em;width:30em; border:thin dotted red; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">
I saw the best minds of my generation Destroyed by madness, starving, hysterical
</div>
Using factory_girl and Rspec with Rails 32010-04-30T00:00:00+00:00http://www.codeography.com/2010/04/30/using-factory_girl-and-rspec-with-rails-3<p><strong>Edit</strong>: As Wes pointed out, the problems I was having were related to using the beta’s of Rails, Rspec and Factory Girl. These are all resolved now, and the only trick is to make sure you use the <a href="https://github.com/thoughtbot/factory_girl_rails">Factory Girl Rails</a> gem. Luckily that is as easy as dropping…</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem 'factory_girl_rails'`
</code></pre></div></div>
<p>…in to your Gemfile. Thanks Wes.</p>
<hr />
<p>Just like anything in Rails 3, start by editing my Gemfile to include Rspec and Factory Girl:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>group :test do
gem "rspec-rails", ">= 2.0.0.beta.8"
gem 'factory_girl', :git => 'git://github.com/thoughtbot/factory_girl.git', :branch => 'rails3'
end
</code></pre></div></div>
<p>Then following the factory_girl documentation I created a new user factory in <code class="highlighter-rouge">spec/factories</code> but got hit with an unexpected error while factory_girl was running her <code class="highlighter-rouge">find_definitions</code> step:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/spec/factories/users.rb:1: uninitialized constant User (NameError)
</code></pre></div></div>
<p>The solution was simple. I noticed in the generated spec_helper Rspec was loading everything nested under <code class="highlighter-rouge">spec/support</code>. So I simply moved my factories directory to <code class="highlighter-rouge">spec/support/factories</code> and I saw the sweet red dots of failing tests.</p>
<p>Time to go make them specs pass.</p>
Fix Snow Leopard's ruby line editor with homebrew's readline2010-03-29T00:00:00+00:00http://www.codeography.com/2010/03/29/fix-snow-leopard-ruby-with-homebrew-readline<p>This is just a very slight adoption of <a href="http://www.jorgebernal.info/development/fixing-snow-leopard-ruby-readline">Jorge Bernal’s awesome post</a>, the only real difference is I use Homebrew to install readline.</p>
<p>First setup <a href="http://github.com/mxcl/homebrew/">homebrew</a>.</p>
<p>Then install readline:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew install readline
</code></pre></div></div>
<p>Wasn’t that nice?</p>
<p>Now, onto fixing Snow Leopard’s Ruby:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -O http://www.opensource.apple.com/tarballs/ruby/ruby-75.tar.gz
tar xvf ruby-75.tar.gz
cd ruby-75/ext/readline/
ruby extconf.rb
make
</code></pre></div></div>
<p>If you get an error Jorge Bernal suggests telling gcc to use the readline in /usr/local</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make readline.o CFLAGS='-I/usr/local/include -DHAVE_RL_USERNAME_COMPLETION_FUNCTION'
cc -arch i386 -arch x86_64 -pipe -bundle -undefined dynamic_lookup -o readline.bundle readline.o -L/usr/local/lib -L/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib -L. -arch i386 -arch x86_64 -lruby -lreadline -lncurses -lpthread -ldl
</code></pre></div></div>
<p>You might want to check that bundle with <code class="highlighter-rouge">otool</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>otool -L readline.bundle
</code></pre></div></div>
<p>When I run that I see the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>readline.bundle:
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/libruby.1.dylib (compatibility version 1.8.0, current version 1.8.7)
/usr/lib/libedit.2.dylib (compatibility version 2.0.0, current version 2.11.0)
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.0)
</code></pre></div></div>
<p>Which happens to be slightly different from Jorge’s, but everything seems to work for me.</p>
<p>Move the existing file out of the way, and replace it with our shiny new bundle:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mv /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/ruby/1.8/universal-darwin10.0/readline.bundle /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/ruby/1.8/universal-darwin10.0/readline.bundle.libedit
cp readline.bundle /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/ruby/1.8/universal-darwin10.0/
</code></pre></div></div>
<p>This was</p>
Simple Capistrano email notifier for rails2010-03-24T00:00:00+00:00http://www.codeography.com/2010/03/24/simple-capistrano-email-notifier-for-rails<p>I needed to send out emails every time I deployed a rails app, and wanted to use the libraries that were already included with rails – e.g. ActionMailer.</p>
<p>My solution was based on some ideas from <a href="http://github.com/pboling/capistrano_mailer">capistrano-mailer</a> and <a href="http://pastie.org/146264">Mislav Marohnić</a> example, but I felt both were overkill for what I need, so here is my very simple, very customizable solution.</p>
<p>Create a file <code class="highlighter-rouge">config/deploy/notifier.rb</code> with the following contents:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$:.unshift File.dirname(__FILE__) + '/../../vendor/rails/actionmailer/lib'
require File.dirname(__FILE__) + '/../../vendor/rails/actionmailer/lib/actionmailer.rb'
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.default_charset = "utf-8"
ActionMailer::Base.smtp_settings = {
:address => "mail.example.com",
:port => 25,
:domain => 'example.com',
:perform_deliveries => true,
:user_name => 'user',
:password => 'secret',
:authentication => :login }
class Notifier < ActionMailer::Base
def deploy_notification(cap_vars)
now = Time.now
recipients cap_vars.notify_emails
from "App Deployments <app_deployments@example.com>"
subject "Deployed to #{cap_vars.host}"
body <<-MSG
Performed a deploy operation on #{now.strftime("%m/%d/%Y")} at #{now.strftime("%I:%M %p")} to #{cap_vars.host}
Deployed to: https://#{cap_vars.host}
MSG
end
end
</code></pre></div></div>
<p>Which is stupid easy to customize, if you’d like to include the multistage info in the email body just edit the MSG and add <code class="highlighter-rouge">#{cap_vars.stage}</code> or any <a href="http://labs.peritor.com/webistrano/wiki/ConfigurationParameter">other variable</a> that was set in the cap file.</p>
<p>Now to get it hooked into your cap file. Simply edit <code class="highlighter-rouge">config/deploy.rb</code> and add the following</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require 'config/deploy/notifier.rb'
# Setup the emails, and after deploy hook
set :notify_emails, ["ampere@example.com", "henry@example.com]
after "deploy", "deploy:notify"
# Create the task to send the notification
namespace :deploy do
desc "Email notifier"
task :notify
Notifier.deliver_deploy_notification(self)
end
end
</code></pre></div></div>
<p>This is not really rails specific, but if I were using Sinatra I would probably not use ActionMailer – something like <a href="http://github.com/benprew/pony">Pony</a> would be a little prettier – but the Capistrano configuration would work just fine.</p>
Howto: Mirror Git to Subversion2010-03-17T00:00:00+00:00http://www.codeography.com/2010/03/17/howto-mirror-git-to-subversion<p>I recently had to setup read only Subversion mirrors for a few Git repositories, and quickly notice the was no consensus on how to do this. Not really happy with the other solutions I found I decided to roll my own using the tools that git already provides. And some cron. Sweet, sweet cron.</p>
<p>A couple of assumptions:</p>
<ul>
<li><code class="highlighter-rouge">/var/svn</code> - The location of your subversion repositories</li>
<li><code class="highlighter-rouge">/home/git/repositories</code> - the Location of your git repositories</li>
<li><code class="highlighter-rouge">/home/git/svn</code> - location of a work repo, actually performs the pull from the origin, merges, and dcommits to subversion.</li>
</ul>
<p>You could easily move these elsewhere if you want, nothing special about their location.</p>
<h1 id="creating-the-mirror">Creating the Mirror</h1>
<p>Lets say we have a project, called Ampere, and we want to setup a mirror.</p>
<p>You have two situations here. Either you are starting with a Subversion repository that you want to move to git, and maintain as a read only mirror. Or you want to create a new Subversion mirror from an existing Git repository.</p>
<h2 id="option-1-create-a-git-repo-from-an-existing-svn-repository">Option 1: Create a git repo from an existing svn repository</h2>
<p>How I exported all of ampere from Subversion and add it to Git, then created a Subversion mirror.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir /home/git/svn
cd /home/git/svn
git svn clone file:///var/svn/ampere/web -T trunk -b branches -t tags ampere
git remote add origin git@example.com:ampere.git
git push origin master
</code></pre></div></div>
<h2 id="option-2-import-git-repository-into-a-new-subversion-repository">Option 2: Import git repository into a new subversion repository</h2>
<p>With a little help from <a href="http://www.kerrybuckley.org/2009/10/06/maintaining-a-read-only-svn-mirror-of-a-git-repository/">Kerry Buckley’s Guide</a> I did the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir /home/git/svn
cd /home/git/svn
git clone /home/git/repositories/ampere.git
cd ampere/
vim .git/config
</code></pre></div></div>
<p>Add the following content to that file:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[svn-remote "svn"]
url = https://example.com/svn/ampere/trunk/
fetch = :refs/remotes/git-svn
</code></pre></div></div>
<p>Then merge the master into the new branch:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git svn fetch svn
git checkout -b svn git-svn
git merge master
git svn dcommit
</code></pre></div></div>
<p>Then rebase that branch to the master, and you can dcommit from the master to svn</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout master
git rebase svn
git branch -d svn
git svn dcommit
</code></pre></div></div>
<h1 id="make-subversion-read-only">Make Subversion read-only</h1>
<p>Made a pre-commit hook that would prevent updating the trunk:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /var/svn/ampere/hooks
vim pre-commit
</code></pre></div></div>
<p>Created the file with these contents</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="nv">REPOS</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
<span class="nv">TXN</span><span class="o">=</span><span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span>
<span class="nv">SVNLOOK</span><span class="o">=</span>/usr/bin/svnlook
<span class="c"># Allow the git user</span>
<span class="nv">$SVNLOOK</span> author <span class="nt">-t</span> <span class="s2">"</span><span class="nv">$TXN</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$REPOS</span><span class="s2">"</span> | /bin/grep <span class="s2">"git"</span> <span class="o">&&</span> <span class="nb">exit </span>0
<span class="c"># Committing to trunk is not allowed</span>
<span class="nv">$SVNLOOK</span> changed <span class="nt">-t</span> <span class="s2">"</span><span class="nv">$TXN</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$REPOS</span><span class="s2">"</span> | /bin/grep <span class="s2">"^U</span><span class="se">\W</span><span class="s2">.*ampere</span><span class="se">\/</span><span class="s2">trunk</span><span class="se">\/</span><span class="s2">"</span> <span class="o">&&</span> /bin/echo <span class="s2">"Error: ampere/trunk is read-only"</span> 1>&2 <span class="o">&&</span> <span class="nb">exit </span>1
<span class="c"># All checks passed, so allow the commit.</span>
<span class="nb">exit </span>0
</code></pre></div></div>
<p>Then made that file executable:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod +x pre-commit
</code></pre></div></div>
<h1 id="merging-into-the-mirror">Merging into the mirror</h1>
<p>In the repository you want to mirror, set the following to force all the merges to be the files from the origin server.</p>
<p>I do this with a copy-merge strategy, this is done with a <a href="http://stackoverflow.com/questions/1910444/git-merge-s-theirs-needed-but-i-know-it-doesnt-exist/1911370#1911370">custom merge driver</a>. Since this is done on the work repository I just set it globally.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /home/git/svn/ampere
git config merge.copy-merge.name 'Copy Merge'
git config merge.copy-merge.driver 'mv %B %A'
git config merge.default copy-merge
</code></pre></div></div>
<h1 id="add-a-cron-job">Add a cron job</h1>
<p>I figured checking for changes once an hour would be plenty:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>30 * * * * /usr/bin/ruby /home/git/svn/mirror.rb ampere >>/home/git/log/mirror-ampere.log 2>&1
</code></pre></div></div>
<h1 id="update-the-missing-mirrorrb-file">Update: The missing mirror.rb file</h1>
<p>Not sure how I forgot this, nor do I have an excuse why it took me so long to add it here.</p>
<p><code class="highlighter-rouge">mirror.rb</code></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env ruby</span>
<span class="nb">require</span> <span class="s1">'date'</span>
<span class="nb">require</span> <span class="s2">"time"</span>
<span class="k">def</span> <span class="nf">usage</span>
<span class="nb">puts</span> <span class="s2">"mirrortosvn <repo-name>"</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">git</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
<span class="nb">system</span><span class="p">(</span><span class="s2">"/usr/bin/git </span><span class="si">#{</span><span class="n">cmd</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">start_sync_log</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="n">str</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="no">DateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">.</span><span class="nf">to_s</span><span class="si">}</span><span class="s2"> Sync </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span>
<span class="n">str</span> <span class="o">+=</span> <span class="s2">"="</span> <span class="o">*</span> <span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="nf">length</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="k">end</span>
<span class="nb">name</span> <span class="o">=</span> <span class="no">ARGV</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">usage</span> <span class="k">if</span> <span class="nb">name</span> <span class="o">==</span> <span class="kp">nil</span>
<span class="nb">puts</span>
<span class="nb">puts</span> <span class="n">start_sync_log</span> <span class="nb">name</span>
<span class="no">Dir</span><span class="p">.</span><span class="nf">chdir</span> <span class="s2">"/home/git/svn/</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="n">git</span> <span class="s2">"pull origin master"</span>
<span class="n">git</span> <span class="s2">"svn dcommit"</span>
</code></pre></div></div>
Running git-daemon on Ubuntu2010-03-15T00:00:00+00:00http://www.codeography.com/2010/03/15/running-git-daemon-on-ubuntu<p>I needed a simple init script for running git daemon under ubuntu 9.10, and after a little searching and tweaking I wound up with the following.</p>
<p>Create a /etc/init.d/git-daemon:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="nb">test</span> <span class="nt">-f</span> /usr/bin/git <span class="o">||</span> <span class="nb">exit </span>0
<span class="nb">.</span> /lib/lsb/init-functions
<span class="nv">GITDAEMON_OPTIONS</span><span class="o">=</span><span class="s2">"daemon --reuseaddr --verbose --base-path=/home/git/repositories/ --detach"</span>
<span class="k">case</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="k">in
</span>start<span class="p">)</span> log_daemon_msg <span class="s2">"Starting git-daemon"</span>
start-stop-daemon <span class="nt">--start</span> <span class="nt">-c</span> git:git <span class="nt">--quiet</span> <span class="nt">--background</span> <span class="se">\</span>
<span class="nt">--exec</span> /usr/bin/git <span class="nt">--</span> <span class="k">${</span><span class="nv">GITDAEMON_OPTIONS</span><span class="k">}</span>
log_end_msg <span class="nv">$?</span>
<span class="p">;;</span>
stop<span class="p">)</span> log_daemon_msg <span class="s2">"Stopping git-daemon"</span>
start-stop-daemon <span class="nt">--stop</span> <span class="nt">--quiet</span> <span class="nt">--name</span> git-daemon
log_end_msg <span class="nv">$?</span>
<span class="p">;;</span>
<span class="k">*</span><span class="p">)</span> log_action_msg <span class="s2">"Usage: /etc/init.d/git-daemon {start|stop}"</span>
<span class="nb">exit </span>2
<span class="p">;;</span>
<span class="k">esac</span>
<span class="nb">exit </span>0
</code></pre></div></div>
<p>Then you can install and start it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo update-rc.d git-daemon defaults
sudo /etc/init.d/git-deamon start
</code></pre></div></div>
RVM info in your prompt2010-03-10T00:00:00+00:00http://www.codeography.com/2010/03/10/rvm-info-in-your-prompt<p>Having jumped on the <a href="http://rvm.beginrescueend.com/">RVM</a> bandwagon, I noticed I was constantly typing <code class="highlighter-rouge">rvm info</code> to see what I was using in any particular instance of the terminal. Which is when I decided I would like to add that info to my prompt – and since I use zsh the RPROMPT seemed like a great place to put this.</p>
<p><img src="/media/rvm-zsh-rprompt.png" alt="RPROMPT with RVM info" /></p>
<p>I wrote a little function to gather the current ruby version, and it will only show the prompt when RVM is installed and you are using a RVM installed ruby. I still have the system instaled ruby as the default, and didn’t want this information to show up when I was using that.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function rvm_ruby_prompt {
if (declare -f rvm > /dev/null) {
if [[ -x $MY_RUBY_HOME ]]
then ruby -v | sed 's/\([^(]*\).*/\1/'
fi
}
}
# Rubies are red, and my rprompt is too
RPROMPT='%{$fg[red]%}$(rvm_ruby_prompt)%{$reset_color%}%'
</code></pre></div></div>
<p>Fun fact: “RPROMPT” stands for Ruby Prompt.</p>
Alias a Class in Ruby2010-03-01T00:00:00+00:00http://www.codeography.com/2010/03/01/alias-a-class-in-ruby<p>I had a collegue looking for a way to alias a class in Ruby. Which I thought was a pretty interseting problem.</p>
<p>My first attempt was using <code class="highlighter-rouge">eval</code>, which really felt to clever:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Daddy; def speak() puts "No!" end; end
%w{Leah Lars}.each {|k| eval "class #{k} < Daddy; end"}
Leah.new.speak
Lars.new.speak
</code></pre></div></div>
<p>Then it dawned on me, everything is an object, even classes. So could it be this simple?</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Daddy; def speak() puts "No!" end; end
Leah = Daddy
Lars = Daddy
Leah.new.speak
Lars.new.speak
</code></pre></div></div>
<p>It actually worked. Yes it is one line longer. But it is extremly readable and does not use <code class="highlighter-rouge">evil</code><em>^H^H^H</em><code class="highlighter-rouge">eval</code></p>
Making Vim play nice with Jekyll's YAML Front Matter2010-02-20T00:00:00+00:00http://www.codeography.com/2010/02/20/making-vim-play-nice-with-jekylls-yaml-front-matter<p><img src="/media/vim-jekyll-yaml-ugly.png" alt="vim-jekyll-yaml-ugly" /></p>
<p>This just looks bad.</p>
<p>I had a little Vim script adventure tonight. I wanted to make the highlighting of the yaml front matter work as it should for Jekyll.</p>
<p>First thing I got hung up on was figuring out how to match multiline regex’s. Which is when I found out about the <code class="highlighter-rouge">\_</code> escape that Vim has, which adds an end of line to the character class it is adjacent to. Now could use the following search to select the yaml:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/^---\_.{-}---$/
</code></pre></div></div>
<p>Which would also find other <code class="highlighter-rouge">---</code> markers in the document, which was no good.</p>
<p>More vimdocs and I finally came across <code class="highlighter-rouge">\%^</code> which conveniently matches start-of-file. Progress!</p>
<p>Once I plug that in, and go look at a few of the built Vim syntax scripts, I discover that I can put them in one handy <code class="highlighter-rouge">syntax match</code> command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>syntax match Comment /\%^---\_.\{-}---$/
</code></pre></div></div>
<p>I discover I can do the same thing with <code class="highlighter-rouge">syntax region</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>syntax region Comment start=/\%^---$/ end=/^---$/
</code></pre></div></div>
<p>And even enable spell checking of my title by tacking on the contains param:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>syntax match Comment /\%^---\_.\{-}---$/ contains=@Spell
</code></pre></div></div>
<p>But now that I figured out how to highlight the text that I care about, I need to figure out which file types use that syntax.</p>
<p>Just apply it to all the markdown files:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>autocmd BufNewFile,BufRead *.markdown syntax match Comment /\%^---\_.\{-}---$/
</code></pre></div></div>
<p>My first take, and it didn’t seem like the best solution. Plus if the markdown file is not in a jekyll blog I don’t want it to highlight the <code class="highlighter-rouge">---</code>’s (since it is probably not yaml)</p>
<p>I try to get tricky, look at the path and if it looks like a jekyll blog I invoke it, and try include the textile file type.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>autocmd BufNewFile,BufRead */_posts/*.textile,*/_posts/*.markdown syntax match Comment /\%^---\_.\{-}---$/
</code></pre></div></div>
<p>Damn, Jekyll allows you to put yaml at the top of any templates, layouts or any other text file you have – and I want those files to work.</p>
<p>Then it dawned on me, I have the jekyll_path defined in my plugin, I just need a way to use that variable in the file pattern. Seems like the only way to do that is construct the command in a string and exec the bad boy. Which lead me to my final solution:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>execute "autocmd BufNewFile,BufRead " . g:jekyll_path . "/* syn match jekyllYamlFrontmatter /\\%^---\\_.\\{-}---$/ contains=@Spell"
</code></pre></div></div>
<p><img src="/media/vim-jekyll-yaml-pretty.png" alt="vim-jekyll-yaml-pretty" /></p>
<p>Much Better.</p>
Convert ugly HTML links to pretty Markdown links2010-02-20T00:00:00+00:00http://www.codeography.com/2010/02/20/convert-ugly-html-links-to-pretty-markdown-links<p>Recently I have been converting a large number of old blog posts to <a href="http://daringfireball.net/projects/markdown/">markdown</a>, and have been writing a bunch of little one off scripts to handle this. One of the things I needed to do was convert a bunch of oddly formatted HTML links to their shiny clean markdown equivalent.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env ruby</span>
<span class="c1"># Convert HTML links to Markdown links</span>
<span class="no">ARGF</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>
<span class="nb">puts</span> <span class="n">line</span><span class="p">.</span><span class="nf">gsub</span> <span class="sr">/<a [^h]*href=["']([^"']*)["'][^>]*>([^<]*)<\/a>/</span><span class="p">,</span> <span class="s2">"[</span><span class="se">\\</span><span class="s2">2](</span><span class="se">\\</span><span class="s2">1)"</span>
<span class="k">end</span>
</code></pre></div></div>
<p>My script follows the standard unix convention, and reads from standard in or a file, and outputs to standard out. To use it you could do something like:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ruby html_links_to_markdown.rb <file.html> > file.markdown
</code></pre></div></div>
<p>I should note, there are a few minor caveats. It will not:</p>
<ul>
<li>replace multi line links</li>
<li>replace links with nested tags. e.g. images <code class="highlighter-rouge"><a href="#"><imr src="fail.png" /></a></code></li>
<li>match any links that have an attribute that starts with ‘h’ before href. I don’t think this is a very high use case. e.g.: <code class="highlighter-rouge"><a height="4" href="#">fail</a></code></li>
</ul>
<p>Those cases should just result in the original <em>ugly</em> links remaining in the document, which can be manually fixed. I thought it was helpful, and handled many of the badly formatted >a< tags that haunted my old posts.</p>
Couple of vim tips2010-02-16T00:00:00+00:00http://www.codeography.com/2010/02/16/couple-of-vim-tips<p>When in command mode, you can grab the word that is under the cursor. Makes search and replace for those long function names painless.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C-r C-w
</code></pre></div></div>
<p>The other little trick I didn’t know about until I accitently brought it up was the command history. This subtle little thing makes a huge diffrence. You can use normal vim movement keys to edit the commands, and when you are done just hit <enter< on the line and it will execute it.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>q:
</code></pre></div></div>
<p>Of course you can do the same thing with search.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>q/
</code></pre></div></div>
Getting irb with readline support on Mac2010-02-01T00:00:00+00:00http://www.codeography.com/2010/02/01/getting-irb-with-readline-support-on-mac<p>I tend to install unix software on the mac the old school way by grabbing the tarball and building it. Well that was fun an all until I discovered that irb didn’t like to honor backspace. Turns out I needed to build and install readline.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -O ftp://ftp.cwru.edu/pub/bash/readline-6.1.tar.gz
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p248.tar.gz
tar -zxvf readline-6.1.tar.gz
cd readline-6.1
./configure
make
sudo make install
cd ..
tar -zxvf ruby-1.8.7-p248.tar.gz
cd ruby-1.8.7-p248
./configure --with-readline-dir=/usr/local --enable-pthread
make
sudo make install
sudo make install-doc
ruby --version
# woohoo!
</code></pre></div></div>
Blogging with Vim2010-01-12T00:00:00+00:00http://www.codeography.com/2010/01/12/blogging-with-vim<p>I was inspired by <a href="http://metajack.im/2009/01/02/manage-jekyll-from-emacs/">Jack Moffitt</a>, and his Jekyll glue for Emacs.</p>
<p>Not willing to let Emacs win this one, I busted out a <code class="highlighter-rouge">:h script</code> and dove into the bizarre world of vim script. And unlike other forays into wacky programming languages, this actually resulted in something that I find useful.</p>
<p>Basically I have two functions, a way to list all the posts in my jekyll blog and a way to make a new post.</p>
<p><code class="highlighter-rouge">:JekyllPost</code> Create a new post, which will create a new buffer populated with a basic template. This does not actually write the file, so if you are like me you can start a post, change your mine and <code class="highlighter-rouge">:q!</code> and have no regrets.</p>
<p><code class="highlighter-rouge">:JekyllList</code> List the posts, opens the vim file system browser in the posts directory. Which lets you quickly search and open any of you previous entries.</p>
<p>If you use git to store you Jekyll blog (and who doesn’t?), you can use the following:</p>
<p><code class="highlighter-rouge">:JekyllCommit</code> Adds and commits all the modified posts in your jekyll blog.</p>
<p><code class="highlighter-rouge">:JekyllPublish</code> Pushes the changes to the remote origin.</p>
<p>I also made a couple of short cuts that save those precious few keystrokes:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>map <Leader>jn :JekyllPost<CR>
map <Leader>jl :JekyllList<CR>
map <Leader>jc :JekyllCommit<CR>
map <Leader>jp :JekyllPublish<CR>
</code></pre></div></div>
<p>You can grab a copy over on <a href="http://github.com/csexton/jekyll.vim">github</a>.</p>
Top 10 Mac apps for non-programmers2010-01-05T00:00:00+00:00http://www.codeography.com/2010/01/05/top-10-mac-apps-for-non-programmers<p>Recently a project manager friend of mine asked what he should get for his shiney new mack book pro, and I came up with the following list. Turns out it was 10 items long. So I was obligated by the internets to turn it into a blog post.</p>
<ol>
<li>
<p><a href="http://adium.im/">Adium</a> for chat (for when you don’t care about video)</p>
</li>
<li>
<p><a href="http://www.obdev.at/products/launchbar/index.html">LaunchBar</a> commercial, for starting apps/switching/everything. TOTALLY worth the money. If you only buy one program for your mac buy this one. If you cant cough up the euros at least use <a href="http://www.blacktree.com/">QuickSilver</a>.</p>
</li>
<li>
<p><a href="http://www.atebits.com/tweetie-mac/">Tweetie for twitter</a> best twitter client, just use the free version.</p>
</li>
<li>
<p><a href="http://www.microsoft.com/mac/products/remote-desktop/default.mspx">Mac RDC client</a> For those who need to remote into windows machines, but
this does it.</p>
</li>
<li>
<p><a href="http://skitch.com/">Skitch</a> is screen capture and markup on steroids. Alghough I am biased to <a href="http://github.com/csexton/captured">Captured</a>, which is for programmers, so it does not fit the criteria.</p>
</li>
<li>
<p><a href="http://cyberduck.ch/">Cyberduck</a> who doesn’t need an ftp client?</p>
</li>
<li>
<p><a href="http://agilewebsolutions.com/products/1Password">1Password</a> commercial, but by far the best password manager/form filler out there.</p>
</li>
<li>
<p><a href="http://dropbox.com">Dropbox</a> simple sync between computers, does great job with <a href="http://lifehacker.com/5063176/how-to-use-dropbox-as-the-ultimate-password-syncer">1Password’s keychain</a>.</p>
</li>
<li>
<p><a href="http://www.omnigroup.com/applications/OmniGraffle/">OmniGraffle</a> commercial, but has a knack of making visio look tard-tastic.</p>
</li>
<li>
<p><a href="http://www.omnigroup.com/omnifocus">OmniFocus</a> commercial, but it is a fantastic GTD program. the WebDAV sync lets me keep my todo list up-to-date on multiple devices.</p>
</li>
</ol>
Open Xcode Project from the Command line2009-10-28T00:00:00+00:00http://www.codeography.com/2009/10/28/open-xcode-project-from-the-command-line<p>When I start to work on a programmign project I am conditioned to open terminal and change to that directory. And when working in xcode I used to run <code class="highlighter-rouge">open MyBigLongProjectName.xcodeproj</code>, but have to deal with the fact that I normally have other files in that directory that start with MyBigLongProjectName–making tab compleation annoying. The solution to this was to make an xcode alias:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>alias xcode="open *.xcodeproj"
</code></pre></div></div>
<p>Now I can switch from terminal to xcode and back with out breaking my pace.</p>
Creating custom ohai plugins2009-10-21T00:00:00+00:00http://www.codeography.com/2009/10/21/creating-custom-ohai-plugins<p>After spending a while googling for how to make a ohai plugin I was forced to Read The Source (tm). So I thought I would put to gether a quick ohai plugin howto.</p>
<p><img src="http://www.codeography.com/media/creating-custom-ohai-plugins.jpg" alt="Ohai, Iz's your new plugin" />
Install ohai
============</p>
<p>You will need the ohai gem installed to use it, so an easy way to do this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gem source -a http://gems.opscode.com/
sudo gem install ohai
</code></pre></div></div>
<h1 id="create-a-simple-plugin">Create a simple plugin</h1>
<p>Ohai plugins use a ruby DSL. The following is about as simple as it gets:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>provides "orly"
orly "yeah, rly."
</code></pre></div></div>
<p>Now that part I found tricky, loading it.</p>
<p>Create a “plugins” folder and put the above code in the <a href="http://github.com/csexton/ohai-plugin-howto/blob/master/plugins/orly.rb">plugins/orly.rb</a> file.</p>
<p>Now to fire up irb (I am assuming you are in the directory that contains the “plugins” folder, if not adjust your path):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>> require 'ohai'
>> Ohai::Config[:plugin_path] << './plugins'
>> o = Ohai::System.new
>> o.all_plugins
>> o.orly #=> "yea, rly"
</code></pre></div></div>
<p>The entire script can be found in <a href="http://github.com/csexton/ohai-plugin-howto/blob/master/orly.rb">orly.rb</a></p>
<p>If you run <code class="highlighter-rouge">o.orly</code> and get <code class="highlighter-rouge">nil</code> the chances are the plugin path is probably incorrect. I battled with this for hours banging my head against the wall. Turns out I just forgot the ‘s’ on the end of ‘./plugins’</p>
<h1 id="using-a-mash">Using a Mash</h1>
<p>Most of the information we want to lookup would be nested in some way, and ohai tends to do this by storing the data in a Mash. This can be done by creating a new mash and setting the attribute to it.</p>
<p>In <a href="http://github.com/csexton/ohai-plugin-howto/blob/master/plugins/canhaz.rb">plugins/canhas.rb</a>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>provides "canhas"
canhas Mash.new
canhas[:burger] = "want"
</code></pre></div></div>
<h1 id="extending-an-existing-plugin">Extending an existing plugin</h1>
<p>Ohai makes it very easy to extend a current plugin with new information. Simply require the plugin you want to extend and extend away. In this example we want to add LOLCODE to languages.</p>
<p>In <a href="http://github.com/csexton/ohai-plugin-howto/blob/master/plugins/lolcode.rb">plugins/lolcode.rb</a>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>provides "languages/lolcode"
require_plugin "languages"
languages[:lolcode] = Mash.new
languages[:lolcode][:version] = "TEH VERSHIONS"
</code></pre></div></div>
<h1 id="working-with-different-platforms">Working with Different Platforms</h1>
<p>One of the main reasons for using ohai is to gather information regardless of the operating system, luckily this is made easy by optionally loading recipes based on the platform. With that platform specific calls abstracted away you can keep your code DRY.</p>
<p>The builtin plugins that come with ohai use the following trick to load platform specific code. It works by creating a base cross-platform plugin that loads the platform specific plugin from a subdirectory.</p>
<p>In <a href="http://github.com/csexton/ohai-plugin-howto/blob/master/plugins/lolcode.rb">plugins/lolcode.rb</a>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>provides "languages/lolcode"
require_plugin "languages"
require_plugin "#{os}::lolcode"
languages[:lolcode] = Mash.new unless languages[:lolcode]
languages[:lolcode][:version] = "TEH VERSHIONS"
</code></pre></div></div>
<p>In <a href="http://github.com/csexton/ohai-plugin-howto/blob/master/plugins/darwin/lolcode.rb">plugins/darwin/lolcode.rb</a>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>provides "languages/lolcode"
require_plugin "languages"
languages[:lolcode] = Mash.new unless languages[:lolcode]
languages[:lolcode][:platform] = "MACKERS"
</code></pre></div></div>
<p>Checkout ohai’s <a href="http://github.com/opscode/ohai/blob/master/lib/ohai/plugins/os.rb">os.rb</a> for the list of platform names.</p>
<p>All of these examples can be found in the <a href="http://github.com/csexton/ohai-plugin-howto/">ohai-plugin-howto github repo</a>, you should be able to clone that and run the ruby scripts in the repo’s root directory.</p>
Install git man pages the easy way2009-09-15T00:00:00+00:00http://www.codeography.com/2009/09/15/install-git-man-pages-the-easy-way<p>There seems to be a few ways to install the git man pages, but these seems to involve some wacky tricks with a copy of the git repo checked out. I wanted to make sure I had the man pages for my exact version of git and just wanted them in place so I could do <code class="highlighter-rouge">git help command</code> and see some pretty helps.</p>
<p>First, figure out your version number. Mine was 1.6.4.2</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git --version
</code></pre></div></div>
<p>Then download the tarball for that version and unzip to your manpage dir:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -O "http://git-core.googlecode.com/files/git-manpages-1.7.7.4.tar.gz"
sudo tar xjv -C /usr/local/share/man -f git-manpages-1.7.7.4.tar.gz
</code></pre></div></div>
<p>If you really don’t want to think, cut-n-paste the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /tmp
curl -O "http://git-core.googlecode.com/files/git-manpages-`git --version | awk '{print $3}'`.tar.gz"
sudo mkdir -p /usr/local/share/man
sudo tar xjv -C /usr/local/share/man -f git-manpages-`git --version | awk '{print $3}'`.tar.bz2
</code></pre></div></div>
The terminal says Grr2009-09-11T00:00:00+00:00http://www.codeography.com/2009/09/11/the-terminal-says-grr<p>I have been building a few things that take a while to compile *cough*<a href="http://llvm.org/">llvm</a>*cough* and started using <a href="http://growl.info/">growl</a> to let me know to stop reading hacker news and go back to doing something useful.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ make ; growlnotify -m "All done!"
</code></pre></div></div>
<p>Then it dawned on me, I should make some aliases. I made two: Yay, for when things were happy to finish. Boo for when I didn’t want something to stop.</p>
<p>I put this in my .bash_login:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>alias yay="growlnotify -m Yay!"
alias boo="growlnotify -m Boo!"
</code></pre></div></div>
<p>Now when I run make I can just do a <code class="highlighter-rouge">make ; yay</code> and it will cheer when it is done. Likewise if I am running one of my deamons that is not supposed to stop running (aka crash) I will do a <code class="highlighter-rouge">server ; boo</code>.</p>
<p>It’s like decorating the homely terminal with some pretty golden growl messages. Suddenly everything is pretty!</p>
<p>This assumes you have growlnotify installed, which can be found on the growl install disk image.</p>
Automating Apple's PackageMaker2009-09-04T00:00:00+00:00http://www.codeography.com/2009/09/04/automating-apple-s-packagemaker<p>This article should have a sub title:</p>
<p>Automating Apple’s PackageMaker: A wonderful way to punish the well intensioned developer.</p>
<p>It seems like PackageMaker is very much an incomplete and buggy tool. I know we are suposed to use drag-n-drop installs, but sometimes that just isn’t a good option. Like if you were creating a system daemon.</p>
<p>Even trying to use the option documented in the usage message fail:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ Flat\ Package\ Editor --extract /tmp/fpm -f test.pkg
Extraction not supported from the command line yet.
</code></pre></div></div>
<p>Granded that is the Flat Package Editor, but as you can see it is just part of PackageMaker, and seemed to have an option I needed – only it is not implemented.</p>
<p>Initially I wanted to make a ruby library to automate creating the pmdoc contents xml files, and possibly some generator scripts. This seemed like it would be straight forward, but I kept running into gotchas.</p>
<p>Amoung my list of complaints when trying to work with a pmdoc:</p>
<p>The relocatable checkbox (and occationally the require reboot option) magically get selected when editing other properties. I notced this every time I would alter the path to the bundle. If I changed “Release” to “Debug” all the other properties would be altered. This got old.</p>
<p>Can’t relaiably track changes in version control, because just opening the package in PackageMaker changes every line in every file contained in the pmdoc bundle.</p>
<p>While you can mark certian paths as relitive, not all of them could be. So you are forced to use absolute paths in some places. If you use a relitive one PackageMaker will crash when trying to build.</p>
<p>This just seemed like a rat hole I would be stuck in, so I abandoned this in favor of a straight command line build.</p>
<p>This means you have to create the root directory, copy all the files into a directory structure that you want for the target and bundle it up. You can specify the recources and scripts directory for the bundle that get included. In theory if you put the right files with the right names in the right place in these directories then they will get use appropratly. This does not always seem to be true.</p>
<p>For example:</p>
<p>I have a scripts folder with a postinstall script:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Scripts/postinstall
</code></pre></div></div>
<p>and I include that on the command line</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>packagemaker --scripts ./scripts/ ...
</code></pre></div></div>
<p>It will get run after the install. Yay!</p>
<p>BUT, if I want a background image I should just have to put the file in the right place</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Resources/background.png
</code></pre></div></div>
<p>And include that resources in the command</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>packagemaker --resources ./scripts/ ...
</code></pre></div></div>
<p>But no dice. If I want the background image to show up I have to un-xar the pkg file:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xar -xf <path_to_pkg> -C <work_dir>
</code></pre></div></div>
<p>Edit the Distribution file</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><background file='background.png' alignment='bottomleft' scaling='none'/>
</code></pre></div></div>
<p>Re-xar the file</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd <work_dir>
xar -cf my_installer.pkg .
</code></pre></div></div>
<p>Currently I have given up on any custom modifacations (like background images), and can do this a a few steps.</p>
<p>Clean up, create the root and populate it with the approprate files</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find ./scripts/ -name '*.DS_Store' -type f -delete
find ./resources/ -name '*.DS_Store' -type f -delete
rm -rf <package_path>
mkdir -p <package_root_path>
cp -R build/<build_dir>/MyApp.app <package_root_path>
cp -R build/<build_dir>/MySecondApp.app <package_root_path>
cp any/requred/files <package_root_path>
</code></pre></div></div>
<p>Change the permission to what they should be on the target:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chown -R root:admin <package_root_path>
sudo chmod -R g+w <package_root_path>
</code></pre></div></div>
<p>Run the package maker build on the command line:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/Developer/usr/bin/packagemaker \
--title "My Installer" \
--version 1.0 \
--filter "\.DS_Store" \
--resources ./resources/ \
--scripts ./scripts/ \
--root-volume-only \
--domain system \
--verbose \
--no-relocate \
-l "/Library/Application Settings/MyApp" \
--target 10.5 \
--id com.example.my_installer.pkg \
--root <package_root_path> \
--out <my_installer.pkg>
</code></pre></div></div>
<p>This will put everything that was in the package_root_path into “/Library/Application Settings/MyApp” on the target. I was doing this because all my files needed to be in that directory. If you need multiple locations through out the drive you can always set -l to “/”, and create the directory tree of the target under your package_root_path.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>If you wanted to do that the directory tree would look something like this:
package_root_path/
/Applicatons/
/MyApp.app
/Library/
/MyApp
</code></pre></div></div>
Detecting native ruby gems with the wrong archetecture2009-06-19T00:00:00+00:00http://www.codeography.com/2009/06/19/detecting-native-ruby-gems-with-the-wrong-archetecture<p>Having recently upgraded to Snow Leopard I have found myself going between my ruby projects and running the tests only to find that the gems I have installed are not 64 bit binaries. Since I am running the ruby that shipped with 10.6 I am running as 64 bit and I would get some nasty wrong archetecture errors. Well I wanted to find a way to go figure out all the gems that did not have <code class="highlighter-rouge">x86_64</code> binary libraries.</p>
<p>Here is the ruby script I came up with:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Gem::all_load_paths.each do |p|
Dir["#{p}/../ext/*.bundle"].each do |f|
s = `file #{f}`
if (!s.include? "for architecture x86_64")
puts s
end
end
end
</code></pre></div></div>
<p>Nice thing about this is it uses <code class="highlighter-rouge">all_load_paths</code> to find where the gems are located, so if you have them installed im multiple places (like <code class="highlighter-rouge">/Library/Ruby/Gems/</code> and <code class="highlighter-rouge">~/.gems</code>) it should find them.</p>
<p>Now if you find gems that are not supported it is normally pretty easy to fix. Here is what I did to fix nokogiri:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Copy the gem to temp
cp -r /Library/Ruby/Gems/1.8/gems/nokogiri-1.3.1/ /tmp/nokogiri
cd /tmp/ext/nokogiri
# Add our archetecture
sed "s/i386/i386 \-arch x86_64/" Makefile > Makefile
make clean
make
# Replace the old binary
sudo cp nokogiri.bundle /Library/Ruby/Gems/1.8/gems/nokogiri-1.3.1/lib/nokogiri/nokogiri.bundle
</code></pre></div></div>
Nice syntax highlighting in Xcode2009-06-09T00:00:00+00:00http://www.codeography.com/2009/06/09/nice-syntax-highlighting-in-xcode<p>I am a big fan of vibrant ink color scheme, and have spent more than a little time so that I can have similar colors when I am looking at code outside of textmate. I have my version of the scheme in Vim, Visual Studio, Trac and now Xcode.</p>
<p><img src="/media/ristoink_xcode.png" /></p>
<p>I couldn’t find anyway to export the color schemes in the Xcode properties so I went poking around. Turns out it is exactly where you would expect it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Library/Application Support/Xcode/Color Themes
</code></pre></div></div>
<p>It has a simple xml plist file, perfect for version control. So I copied it to my dotfiles git repository and symlinked it. So if you want my latest color scheme head over to github and take a look. Or you could just <a href="http://github.com/csexton/dotfiles/raw/master/xcode/RistoInk.xccolortheme">download it</a>.</p>
<p>To install it just drop it into the library directory above.</p>
Vim Tip - VimGrep and QuickList2009-06-05T00:00:00+00:00http://www.codeography.com/2009/06/05/vim-tip-vimgrep-and-quicklist<p>I have known about the vimgrep command for a while, but it was always a little awkward. Well that has all changed now that I know about the QuickFix window.</p>
<p>Take a gem project, I want to search through all the ruby files:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:vimgrep my_method **/*.rb
</code></pre></div></div>
<p>Which jumps to the first one. But (unbeknownst to me) it also populates the quick list. You can bring up this fancy window with a <code class="highlighter-rouge">:cw</code></p>
<p>Then you can simply navigate to the line you want to look at and hit <code class="highlighter-rouge">enter</code>.</p>
<p>Suh-weet.</p>
<p>But it gets better. Often I want to look for a couple of keywords. I can keep adding to the quick list by using <code class="highlighter-rouge">vimgrepadd</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:vimgrep your_method **/*.rb
</code></pre></div></div>
<p>Then you end up with the results of both in your quick list window, which is a simple <code class="highlighter-rouge">C-w C-w</code> away.</p>
Working with binary data in irb2009-06-03T00:00:00+00:00http://www.codeography.com/2009/06/03/working-with-binary-data-in-irb<p>Since I have been workign on a ruby port of a windows program that has a binary format, I find myself having to examine the memory contents in Visual Studio and try to reproduce the same output in ruby. Well, maybe it is years of pratice, but I find it much easier to read the hex output than the octal that ruby uses. This is something I normally want when working in IRB or as fixture data in my tests. So to make this a little easier I extended Integer and String. I wound up dumping this code into my .irbrc file so I could easily cut-n-paste the memory from windows.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Integer
def to_binary_s
bits = self.to_s(2)
prepend = (8 - bits.length % 8)
bits = ('0' * prepend) + bits
return [bits].pack('B*')
end
end
class String
def read_hex_s
self.gsub(" ", "").hex.to_binary_s
end
def to_hex_s
self.unpack("H*")[0]
end
end
</code></pre></div></div>
Setting up cgit under Ubuntu2009-05-30T00:00:00+00:00http://www.codeography.com/2009/05/30/setting-up-cgit-under-ubuntu<p>I tried gitweb and wasted most of a day trying to get apache to stop escaping “;” with “%3”, took a hack at a few of the php based git browsers – no luck. That was until I came accross cgit.</p>
<p>First setup the prereques. I had most of what I needed but was missing libcurl, so I ran the following command to add that. I am sure you will need a few other like git-core and build-essentials.
sudo apt-get install libcurl4-openssl-dev</p>
<h2 id="building-cgit">Building cgit</h2>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone git://github.com/metajack/cgit.git
cd cgit/
git submodule init
git submodule update
make
</code></pre></div></div>
<p>I skip the make install step because I put the binary in a seprate cgi-bin directory anyway.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo cp ./cgit /usr/lib/cgi-bin/cgit.cgi
</code></pre></div></div>
<p>Of course if you use a different location for your cgi-bin you will want to put that in the above command</p>
<p>If /var/www/htdocs/ is your docroot (which mine is) you will want to move the css and png files there:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp ./cgit.css /var/www/htdocs/
cp ./cgit.png /var/www/htdocs/git-logo.png # the default logo
</code></pre></div></div>
<h2 id="configure-cgit">Configure cgit</h2>
<p>Create a file at /etc/cgit and add the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virtual-root=/git/
enable-index-links=1
enable-log-filecount=1
enable-log-linecount=1
snapshots=tar.gz tar.bz zip
# List of repositories
repo.url=red_baron
repo.path=/home/git/repositories/red_baron.git
repo.desc=Ace of the skies
repo.owner=Reb Baron
repo.group=project1
repo.url=sub1
repo.path=/home/git/repositories/sub1.git
repo.desc=Sub1 of Project1
repo.owner=Joe Cool
repo.url=sub1
repo.path=/home/git/repositories/sub1.git
repo.desc=Sub2 of Project1
repo.owner=Snoopy
</code></pre></div></div>
<h2 id="configure-apache">Configure Apache</h2>
<p>Add the following under your virtual host tag:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # Add the cgi-bin if you don't have one already
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
# Add the trailing slash
RewriteRule ^/git$ /git/ [R]
# Pretty urls
RewriteRule ^/git/(.*)$ /cgi-bin/cgit.cgi/$1 [PT]
</code></pre></div></div>
<p>At this point you should be able to restart apache and browse to your git repos at http://hostname/git</p>
Speedy Bash Prompt: Git and Subversion Integration2009-05-26T00:00:00+00:00http://www.codeography.com/2009/05/26/speedy-bash-prompt-git-and-subversion-integration<p>I had tried using a <a href="http://www.entropy.ch/blog/Developer/2009/03/30/Git-and-SVN-Status-in-the-Bash-Prompt.html">number</a> of <a href="http://ciaranm.wordpress.com/2008/07/16/git-and-subversion-information-in-the-bash-prompt/">other</a> bash scripts to display git and svn info in the prompt, but things had become pretty sluggish. Sure things would cache after the first time I cd’d into the directory, but often I was stuck waiting while that first try happened. I couldn’t take it any more. I wanted some info still in the prompt, but I didn’t need that much, so I trimmed things down.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scm_ps1() {
local s=
if [[ -d ".svn" ]] ; then
s=\(svn:$(svn info | sed -n -e '/^Revision: \([0-9]*\).*$/s//\1/p' )\)
else
s=$(__git_ps1 "(git:%s)")
fi
echo -n "$s"
}
export PS1="\[\033[00;32m\]\u\[\033[00;32m\]@\[\033[00;32m\]\h:\[\033[01;34m\]\w \[\033[31m\]\$(scm_ps1)\[\033[00m\]$\[\033[00m\] "
</code></pre></div></div>
<p>This requires you have the git bash compleation script installed for the <code class="highlighter-rouge">__git_ps1</code> command. Which I have on OS X from MacPorts (if you used the +bash_compleation option) and from Apt on Ubuntu.</p>
<p>You will need to source these in your .bash_login.</p>
<p>For all the bashy compleations:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if [ -f /opt/local/etc/bash_completion ]; then
. /opt/local/etc/bash_completion
fi
</code></pre></div></div>
<p>Just for git:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if [ -f /opt/local/etc/bash_completion.d/git ]; then
. /opt/local/etc/bash_completion.d/git
fi
</code></pre></div></div>
<p>If interested check out the home/bash_login script in my <a href="http://github.com/csexton/dotfiles/tree/">dotfiles project</a>.</p>
Pure Ruby CRC-32/ADCCP (CRC-32/PKZIP)2009-05-22T00:00:00+00:00http://www.codeography.com/2009/05/22/pure-ruby-crc32-adccp-pkzip<p>I ported what I beleive is the CRC-32/ADCCP (a.k.a CRC-32/PKZIP) to ruby. I had been doing communication with a server that required a CRC signature be calculated and sent along with the data only to discover that Zlib.crc32 would not work.</p>
<p>Luckily the folks who made the pure Ruby port of Zlib, Zliby, provided a good starting point with their crc32 implementation.</p>
<p>After a fair amount of head scratching and saying of bad words here is what I came up with. Seems to work just fine for my communication.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def self.crc32adccp(string, crc=0)
raise RangeError.new if (crc > 2**128 - 1)
string.each_byte do |byte|
temp1 = (crc >> 8) & 0x00FFFFFF
temp2 = crc_table[(crc ^ byte) & 0xff];
crc = temp1 ^ temp2
end
crc
end
</code></pre></div></div>
<p>If you don’t want to include the crc table in your code you can prefix the crc_table with “Zlib.” and require ‘zlib’ but if you are like me and would prefer to have uglier code with less dependencies you can include the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def self.crc_table
[ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d]
end
</code></pre></div></div>
<p>Here’s a rspec to see how to use it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>it "should create a valid crc" do
# I gathered this string and crc from the server directly to serve
# as fixture data
data = "\001\000\000\000\000\340\001\000\000"
crc32adccp(data).should eql 3234217804
end
</code></pre></div></div>
Working with FILETIME in Ruby2009-05-20T00:00:00+00:00http://www.codeography.com/2009/05/20/working-with-filetime-in-ruby<p>Recently I have had to deal with the windows FILETIME struct in ruby.</p>
<p>MSDN defines this guy as “a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).”</p>
<p>Well, the easy thing to do is add a method to the Time class that can convert to the format:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Time
# Convert the time to the FILETIME format, a 64-bit value representing the
# number of 100-nanosecond intervals since January 1, 1601 (UTC).
def wtime
self.to_i * 10000000 + 116444736000000000
end
# Create a time object from the FILETIME format, a 64-bit value representing
# the number of 100-nanosecond intervals since January 1, 1601 (UTC).
def self.from_wtime(wtime)
Time.at((wtime - 116444736000000000) / 10000000)
end
end
</code></pre></div></div>
<p>Now I can do fancy things like:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>some_bindata_struct.time = Time.now.wtime
</code></pre></div></div>
ssh-keyput2009-05-19T00:00:00+00:00http://www.codeography.com/2009/05/19/ssh-keyput<p>That’s pronounced “shush-kaput”</p>
<p>If there is one thing I like it is setting up ssh to use my public key so that I don’t have to type a password when login to a server. This wasn’t too hard, but since OSX does not have ssh-copy-id by default I would have to pull up the instructions every time to make sure I remembered the file names and permissions just right.</p>
<p>So last night I made a ruby gem to remember how to do it for me, ssh-keyput</p>
<p>Now all I’s got to do to copy my public key is:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ssh-keyput chris@server.com
</code></pre></div></div>
<p>To install all you need is a simple gem install:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gem install csexton-ssh-keyput -s http://gems.github.com
</code></pre></div></div>
<p>It is nothing but a glorified wrapper for a few shell commands, but it is much easier to remember</p>
Working with binary data in Ruby2009-05-02T00:00:00+00:00http://www.codeography.com/2009/05/02/working-with-binary-data-in-ruby<p>Recently I found my self having to work with binary data in Ruby, but have found myself confused and frustrated by a few things. Luckily this during recent experiment I discovers a few tricks that really help me.</p>
<h2 id="view-binary-data-in-hex">View binary data in hex</h2>
<p>When working in the Visual Studio debugger I prefer to view memory in hex, so I found it awkward to compare with the decimal escapes that Ruby uses.</p>
<p>But String#unpack has the H format. Since the documentation described it as “extract hex nibbles from each character” I didn’t expect it to do what I wanted, but it does. For example:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>> "\322\204\371\225Q".unpack("H*")
=> ["d284f99551"]
</code></pre></div></div>
<h2 id="parsing-data-into-structs">Parsing data into structs</h2>
<p>While you <em>can</em> do this with String#unpack and Array#pack, that frankly blows. Luckily I came across Dion Mendel’s awesome <a href="http://bindata.rubyforge.org/">binutils gem</a>.</p>
<p>Where I was able to take this C struct:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struct ServerData
{
WORD StructSize;
DWORD ErrorCode;
char ErrorMsg[100];
char ServerIPAddr[16];
WORD ServerPort;
BYTE Reserved[100];
digest Signature;
};
</code></pre></div></div>
<p>And rewrite it in ruby:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class ServerData < BinData::Record
uint16le :struct_size, :value => lambda { num_bytes }
uint32le :error_code
string :error_msg, :length => 100
string :server_ip_addr, :length => 16
uint16le :server_port
string :reserved, :length => 100
string :signature, :length => 16
end
</code></pre></div></div>
<p>The only hard part in the process was figuring out what datatypes to use for the windows types. Here are a few I had to use:</p>
<ul>
<li>WORD -> uint16le</li>
<li>DWORD -> uint32le</li>
<li>char[n\ -> string (with length ‘n’)</li>
<li>BYTE[n\ -> Binary data (with length ‘n’)</li>
<li>INT -> int32le</li>
</ul>
<p>As I was working my way thought the string I found it helpful to test the parsing one element at a time and make sure that is working. I would comment out all the elements but the first and try</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class LittleExample < BinData::Record
uint16le :word_var
end
>> a = LittleExample.new
>> a.read( "\370\000\364\001\000\000")
=> {"word_var"=>248}
</code></pre></div></div>
<p>One slick feature of BinData::Record is the ability to set default values. You can see in the ServerData example above I need to report the size of the struct, and since there are not dynamic length elements I can simply call the num_bytes method on the record:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class LengthData < BinData::Record
uint16le :struct_size, :value => lambda { num_bytes }
end
>> len = LengthData.new
=> {"struct_size"=>2}
</code></pre></div></div>
Browse vim command history2009-04-16T00:00:00+00:00http://www.codeography.com/2009/04/16/browse-vim-command-history<p>This had happened accidentily a few times, and everytime I thought the feature was really cool but could not figure out how to bring it up.</p>
<p>Well I finaly got it. In command mode enter <C-f> and you will get a fancy history.</p>
Update the locate DB on OS X2009-04-14T00:00:00+00:00http://www.codeography.com/2009/04/14/update-the-locate-db-on-os-x<p>Turns out OS X does not have an <code class="highlighter-rouge">updatedb</code> command like linux has, so I was stumped on how to update the locate database.</p>
<p>After a little digging I found the command we needed:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /usr/libexec/locate.updatedb
</code></pre></div></div>
<p>It is a little paranoid about revealing file names, but it is happy to index everything for you.</p>
Development environment for OS X2009-04-13T00:00:00+00:00http://www.codeography.com/2009/04/13/development-environment-for-os-x<p>I recently blew away all my developer tools, /usr/local and /opt (mac ports), and wanted to start with a clean install of my development tools. The following is my configuration for Ruby, Rails, iPhone and C++ development:</p>
<p>Cleanup was done by removing the developer tools with the include perl script:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /Developer/Library/uninstall-devtools --mode=all
</code></pre></div></div>
<p>Then I deleted /opt, which nuked all of the old macports I had installed.</p>
<p>Then I cleaned out everything I thought I could from /usr/local/. I was mostly interested in removing the include, share, and lib folders from there. Just to be safe I didn’t delete them outright, rather I moved them to a ‘deleteme’ directory while I made sure I could get everything working again.</p>
<p>Once cleanup was done, it was onto the reinstall.</p>
<p>Install the developer tools, I grabbed the latest by downloading the iPhone SDK from the <a href="http://developer.apple.com/iphone/">ADC</a></p>
<h2 id="install-macports">Install MacPorts</h2>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo port -v selfupdate
</code></pre></div></div>
<h2 id="install-the-ports">Install the ports</h2>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo port install subversion +bash_completion git-core +bash_completion+doc+gitweb+svn ruby rb-rubygems rb-rake curl xercesc boost log4cpp cppunit mysql +server
</code></pre></div></div>
<h2 id="install-the-gems">Install the gems</h2>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gem install rails
</code></pre></div></div>
Resolve .local domains in Ubuntu2009-04-11T00:00:00+00:00http://www.codeography.com/2009/04/11/resolve-.local-domains-in-ubuntu<p>Recently had a problem where i couldn’t resolve any of our internal “.local” domain names. The weird thing was I could add a dns search to resolve.conf and resolve it by pinging the host name, but anytime I tried to use the fdqn it would fail</p>
<p>Turns out the problem is the avahi-daemon. This can be disabled by editing</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/defaults/avahi-daemon
</code></pre></div></div>
<p>and changing the AVAHI_DAEMON_START to 0.</p>
<p>Then you can remove the rc scripts with the following command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo update-rc.d -f avahi-daemon remove
</code></pre></div></div>
Installing Git on OS X with the fancy stuff2009-04-11T00:00:00+00:00http://www.codeography.com/2009/04/11/installing-git-on-os-x-with-the-fancy-stuff<p>To install git with macports use the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo port install git-core +doc+svn+bash_completion+gitweb
</code></pre></div></div>
Create a new post in Jekyll2009-04-11T00:00:00+00:00http://www.codeography.com/2009/04/11/create-a-new-post-in-jekyll<p>Worst thing about Jekyll is making a blog post by hand, so I wanted a clever way to automate it. I started with modifying jekyll it self to have a –post option, but that didn’t feel like the right place to put things. I am currently using a rake task that I borrowed from Dr. Nic’s <a href="http://github.com/drnic/jekyll_generator/tree/master">jekyll-generator</a>, the extended it a little bit. The biggest improvement is looking for the EDITOR variable and loading the new post in that editor for quick editing.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>desc "Creates a new _posts file using TITLE='the title' and today's date. JEKYLL_EXT=markdown by default"
task :post do
ext = ENV['JEKYLL_EXT'] || "markdown"
unless title = ENV['TITLE']
puts "USAGE: rake post TITLE='the post title'"
exit(1)
end
post_title = "#{Date.today.to_s(:db)}-#{title.downcase.gsub(/[^\w]+/, '-')}"
post_file = File.dirname(__FILE__) + "/_posts/#{post_title}.#{ext}"
File.open(post_file, "w") do |f|
f << <<-EOS.gsub(/^ /, '')
---
layout: post
title: #{title}
---
EOS
end
if (ENV['EDITOR'])
system ("#{ENV['EDITOR']} #{post_file}")
end
end
</code></pre></div></div>
Getting Started with Jekyll2009-03-30T00:00:00+00:00http://www.codeography.com/2009/03/30/getting-started-with-jekyll<p>Install jekyll</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo gem install mojombo-jekyll -s http://gems.github.com/ -s http://gems.rubyforge.org/
</code></pre></div></div>
<p>Setup a site</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mkdir site
$ cd site
</code></pre></div></div>
<p>Make the base layout</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mkdir _layouts
</code></pre></div></div>
<p>Create a file called base.html in site/_layouts:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"></span>
<span class="nt"><html</span> <span class="na">xmlns=</span><span class="s">"http://www.w3.org/1999/xhtml"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><title></span>{ {; page.title }}<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
{ { content }}
<span class="nt"></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p>Make an about page:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir about
</code></pre></div></div>
<p>Create a file called index.html in site/about:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
layout: base
---
<h1>Getting started with Jekyll</h1>
<p>I am not afraid of the command line</p>
</code></pre></div></div>
<p>Now you should be able to run jekyll from your site directory</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jekyll
</code></pre></div></div>
<p>If that works, try running the built in server and take a look</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jekyll --server
</code></pre></div></div>
<p>And browse to <a href="http://localhost:4000/about">http://localhost:4000/about</a></p>
<h2 id="add-some-style">Add some style</h2>
<p>Well that’s not very pretty, but shows that it works. Lets add some style. I like to use <a href="http://blueprintcss.org/">Blueprint CSS</a>, so I will add that. Feel free to use your own stylesheets, but this will give you a good starting point. You can download them from their website, or use the following wget’s to just get up and running quick:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir stylesheets
cd stylesheets
wget http://blueprintcss.org/blueprint/screen.css
wget http://blueprintcss.org/blueprint/print.css
wget http://blueprintcss.org/blueprint/ie.css
cd ..
</code></pre></div></div>
<h2 id="add-some-syntax-highlighting">Add some syntax highlighting</h2>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo port install py-pygments
cd stylesheets
wget http://tom.preston-werner.com/css/syntax.css
</code></pre></div></div>
<h2 id="add-a-feed">Add a feed</h2>
<p>In the root of your site folder, create an ‘atom.xml’ file with the following:</p>
<pre>
---
layout: nil
---
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Codeography</title>
<link href="http://codeography.com/atom.xml" rel="self"/>
<link href="http://codeography.com/"/>
<updated>{{site.time | date_to_xmlschema }}</updated>
<id>http://codeography.com/</id>
<author>
<name>Christopher Sexton</name>
<email></email>
</author>
{% for post in site.posts %}
<entry>
<title>{{ post.title }}</title>
<link href="http://codeography.com"/>
<updated>{{post.date | date_to_xmlschema }}</updated>
<id>http://codeography.com{{ post.id }}</id>
<content type="html">{{ post.content | xml_escape }}</content>
</entry>
{% endfor %}
</feed>
</pre>
shush-kaput2009-01-24T00:00:00+00:00http://www.codeography.com/2009/01/24/shush-kaput<p>If there is one thing I like it is setting up ssh to use my public key so that I don’t have to type a password when login to a server. This wasn’t too hard, but since OSX does not have ssh-copy-id by default I would have to pull up <a href="http://www.webficient.com/2007/11/16/mac-and-ssh-keys">the instructions</a> every time to make sure I remembered the file names and permissions just right.</p>
<p>So last night I made a ruby gem to remember how to do it for me, <a href="http://github.com/csexton/ssh-keyput/">ssh-keyput</a></p>
<p>Now all I’s got to do to copy my public key is:</p>
<p>$ ssh-keyput chris@server.com</p>
<p>To install all you need is a simple gem install:</p>
<p>$ gem install csexton-ssh-keyput -s http://gems.github.com</p>
<p>It is nothign bu a gloafied wrapper for a few shell commands, but it is much easier to remember</p>
Programming for fun?2008-10-02T00:00:00+00:00http://www.codeography.com/2008/10/02/programming-for-fun<p>I’ve been working on the cookbook application for the wife and couple interesting things.</p>
<p>I use Dreamhost, and while they rock in alot of ways they won’t let me have any long running processes. I wanted to add full text search to my cookbook (because if you can’t find the recipe you want, what good is a cookbook) and I couldn’t use the likes of Sphinx or Ferret. But if I changed my DB to MySQL (which dreamhost does provide) I can use the built in fulltext search. It is a little hackish, and MySQL specific but it works and is plenty fast for my needs.</p>
<p>I had to do two things:</p>
<p>1) Add a FULLTEXT index to my migration</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> def self.up
...
execute 'ALTER TABLE recipes ENGINE = MyISAM'
execute 'CREATE FULLTEXT INDEX ft_idx_recipes ON recipes(title,ingredients,directions)'
end
def self.down
execute 'ALTER TABLE recipes DROP INDEX ft_idx_recipes'
execute 'ALTER TABLE recipes ENGINE = InnoDB'
drop_table :recipes
end
</code></pre></div></div>
<p>2) In my recipes controller in the search action I have the following line</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> @recipes = Recipe.find_by_sql("SELECT \* FROM recipes WHERE MATCH (title, ingredients, directions) AGAINST ('#{query.gsub(/'/, "''")}');")
</code></pre></div></div>
<p>The gsub bit is to sanitize the sql. Pretty simple really, and if I ever want to replace it all I need to do is modify the controller.</p>
<p>I found out today that the Bort guys added OpenID support to the project. Which would normally involve some obscure svn/patch hijinks to deal with, but thanks to git I can just grab their changes (I did fork <a href="http://github.com/csexton/cookbook/tree/master">my project</a> from theirs to start with).</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git branch openid # incase I screw things up
git checkout openid # use the new branch
git pull git://github.com/fudgestudios/bort.git master
# Fix any conflicts and merge back to master
</code></pre></div></div>
<p>Finally, did everyone know you can put alias in the .gitconfig file? Well, you never told me.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> [alias]
co = checkout
ci = commit
st = status
</code></pre></div></div>
Instiki 0.13 Installation on Dreamhost with Passenger2008-09-21T00:00:00+00:00http://www.codeography.com/2008/09/21/instiki-0.13-installation-on-dreamhost-with-passenger<p>Running Instiki on Dreamhost has gotten much easier since they have added Passenger (mod_rails).</p>
<p>Create a new fully hosted domain on dreamhost. Something like wiki.domain.com.</p>
<ul>
<li>Check the “Ruby on Rails Passenger (mod_rails)” box.</li>
<li>In the Specify your web directory enter “wiki.yourdomain.com/instiki/public”</li>
</ul>
<p>This <strong>will create</strong> the wiki.domain.com folder in the user’s home directory. Login to your shell account and do the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd wiki.yourdomain.com
svn checkout svn://rubyforge.org/var/svn/instiki/instiki/trunk/ instiki
cd instiki
rake db:migrate RAILS_ENV=production
</code></pre></div></div>
<p>Open wiki.yourdomain.com in your browser and set up the wiki.</p>
<p><a href="http://www.wiki.fuzzymonk.com/wiki/published/HomePage">Chuckle</a></p>
Using sqlite as a production DB2008-09-20T00:00:00+00:00http://www.codeography.com/2008/09/20/using-sqlite-as-a-production-db<p>I wanted to use sqlite3 as my production DB for a <a href="http://github.com/csexton/cookbook/tree/master">little web app</a> that I am working on. Wasn’t sure exactly what was going to be needed, but turns out if you add the following to your cap recipie you are all set. Shiny!</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>task :after_update_code do
run "ln -s #{deploy_to}/#{shared_dir}/db/production.sqlite3 #{current_release}/db/production.sqlite3"
end
</code></pre></div></div>
<p>You might notice I am using bort as the starting point for cookbook. They really have done everything I need, in the way I need. Since I am using it with Dreamhost (read: Passenger) and git I really didn’t need to undo ANYTHING.</p>
Building Visual Studio Projects with Rake2008-09-20T00:00:00+00:00http://www.codeography.com/2008/09/20/building-visual-studio-projects-with-rake<p>We are building a Rails applicaiton that has a C++ client developed under windows, and needed a nice way to script things. Since the web side of the project was in rails it seemed natural to use rake to build the C++ stuff. Pretty simple, but in order for the devenv to get loaded we had to load some of the envorment varables up for rake. Once that was done everyting has been easy.</p>
<p>My Rakefile:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Visual Studio 2008 Environment Settings:
ENV["VSINSTALLDIR"] = 'C:\Program Files\Microsoft Visual Studio 9.0'
ENV["VCINSTALLDIR"] = 'C:\Program Files\Microsoft Visual Studio 9.0\VC'
ENV["DevEnvDir"] = 'C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE'
ENV["PATH"] = 'C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE;C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN;C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools;C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 9.0\VC\VCPackages;' + ENV["PATH"]
ENV["INCLUDE"] = 'C:\Program Files\Microsoft Visual Studio 9.0\VC\ATLMFC\INCLUDE;C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;C:\Program Files\boost\boost_1_35_0'
ENV["LIB"] = 'C:\Program Files\Microsoft Visual Studio 9.0\VC\ATLMFC\LIB;C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;C:\Program Files\boost\boost_1_35_0\lib'
ENV["LIBPATH"] = 'C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 9.0\VC\ATLMFC\LIB;C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB'
# WiX Environment Settings
WIX_PATH="\"C:/Program Files/Windows Installer XML v3/bin\""
CANDLE= WIX_PATH + "candle"
LIGHT = WIX_PATH + "light"
desc "Build the project in release"
task 'release' do
system 'VCBuild path/to/project.vcproj Release /rebuild /nologo'
end
task :default => [:release]
</code></pre></div></div>
Git on OS X2008-07-13T00:00:00+00:00http://www.codeography.com/2008/07/13/git-on-os-x<p>I’ve been tinkering with git, and git-svn. Starting to figure out how to cope, and am hopeful that the real coolness of distributed systems will become apparent soon.</p>
<p>The real trick, was finally getting it to install with the options I had hoped for: svn integration, command completion and a custom bash prompt.</p>
<p>First, to install it via Mac Ports (other articles I read had either “+svn” or “+ bash_completion”, but not both)</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo port install git-core +bash_completion +svn +doc
</code></pre></div></div>
<p>Set up <a href="http://unboundimagination.com/Current-Git-Branch-in-Bash-Prompt">Arya Asemanfar’s</a> bash prompt and add git command completion.</p>
<p>I added the following to .bash_login</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Command Completion
source /opt/local/etc/bash_completion.d/git
# Custom Prompt
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^\*]/d' -e 's/\* \(.\*\)/(git::\1)/'
}
parse_svn_branch() {
parse_svn_url | sed -e 's#^'"$(parse_svn_repository_root)"'##g' | awk -F / '{print "(svn::"$1 "/" $2 ")"}'
}
parse_svn_url() {
svn info 2>/dev/null | grep -e '^URL\*' | sed -e 's#^URL: \*\(.\*\)#\1#g '
}
parse_svn_repository_root() {
svn info 2>/dev/null | grep -e '^Repository Root:\*' | sed -e 's#^Repository Root: \*\(.\*\)#\1\/#g '
}
export PS1="\[\033[00m\]\u@\h:\[\033[01;34m\]\w \[\033[31m\]\$(parse_git_branch)\$(parse_svn_branch)\[\033[00m\]$\[\033[00m\] "
</code></pre></div></div>
<p>Once you get to that point, I recommend heading over to <a href="http://www.intridea.com/2008/6/18/going-rogue-with-git-svn-on-os-x">Intridea’s</a> Getting Rogue with git-svn, it has been a great help for me.</p>
CBT Error2008-07-13T00:00:00+00:00http://www.codeography.com/2008/07/13/cbt-error<p>I was trying to complete some of the mandentory online training required by my company and got the following error on their website:</p>
<p><img src="http://photos.fuzzymonk.com/blog/image/595/CBT-Windows-Error.jpg" class="picture" /></p>
<p>Best part is they support IE, Firefox under windows and Navigator under Linux. Not really sure why Safari and Firefox on OS X wouldn’t work for them.</p>
Javascript Code Prettifier2008-06-13T00:00:00+00:00http://www.codeography.com/2008/06/13/javascript-code-prettifier<p>I really liked the idea of the <a href="http://google-code-prettify.googlecode.com/svn/trunk/README.html">Javascript Code Prettifier</a>, and I really like my <a href="http://www.fuzzymonk.com/svn/settings/vim/vimfiles/colors/ristoink.vim">personal color scheme</a>, so I wanted to combine them. I thought it was turned out pretty neat, espcially since it only took about 20 min of tinkering to get everything sorted out, so I wanted to contribute back to the author – but he provides no simple way to do that, so I will tell you about it. You who are prolly only coming here for the pics of Leah (see previous post).</p>
<p>Here is my color scheme for JS Prettifier:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.str { color: #66FF00; }
.kwd { color: #AAAAAA; }
.com { color: #AA66FF; }
.typ { color: #DDE93D; }
.lit { color: #339999; }
.pun { color: #AAAAAA; }
.pln { color: #FFFFFF; }
.tag { color: #AAFFFF; }
.atn { color: #FF6600; }
.atv { color: #66FF00; }
.dec { color: #FF6600; }
pre.prettyprint { padding: 2px; border: 1px solid #888; background-color: #000000;}
</code></pre></div></div>
<p>The only other change is, I wanted the tags surrounding the code to be <pre class=”code”> instead of <pre class=”prettyprint”>, because I just type raw html and that would be shorter and easier to remember (at least for me).</p>
<p>You can see those files directly:</p>
<ul>
<li><a href="http://www.fuzzymonk.com/styles/prettify.css">prettify.css</a></li>
<li><a href="http://www.fuzzymonk.com/js/prettify.js">prettify.js</a></li>
</ul>
<p>Check out some fun ruby code (and it’s whitespace independence):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hash = { :water => 'wet', :fire => 'hot' }
puts hash[:fire] # Prints: hot
hash.each_pair do |key, value| # Or: hash.each do |key, value|
puts "#{key} is #{value}"
end
# Prints: water is wet
# fire is hot
hash.delete :water # Deletes :water => 'wet'
hash.delete_if {|k,value| value=='hot'} # Deletes :fire => 'hot'
</code></pre></div></div>
Dynamic Cheese Grater2008-06-10T00:00:00+00:00http://www.codeography.com/2008/06/10/dynamic-cheese-grater<p>I decided I’d like to access my home computer from work, specifically I wanted to be able to ssh into the machine. I used to do this by setting up a dynamic host name and just leaving my computer on all day long, but that hardly seemed like the best way to deal with it. More specifically, I didn’t really want to pay for the electricity of running that thing all day long. So I decided to look into what I needed to do to get Wake-on-LAN to work with my Power Mac and FiOS modem.</p>
<ul>
<li>First was to go back to Dyndns.com and get a hostname for my compy. I like the “homeip.net” ones, cause, it is in my home. </li>
<li>Configure my router to port forward ssh (tcp on port 22) </li>
<li>And wake-on-lan (udp on port 9) to my desktop.</li>
<li>Configure OS X to allow ssh (System Prefrences - Sharing - Check “Remote Login”) </li>
<li>And to allow wake-on-lan (System Prefrences - Energy Saver - Show Details - Check “Wake for Ethernet…”</li>
</ul>
<p>Now I just needed a way to wake it up. First I played with <a href="http://www.dslreports.com/wakeup">this web page</a>, which worked, but required me to type in my Desktop’s MAC address every time. Uncool. Then I found a little perl script that could do it, sorta. At that point I realized this was a job for ruby. And lo and behold I found K. Kodama <a href="http://www.math.kobe-u.ac.jp/~kodama/tips-WakeOnLAN.html">WOL Class</a>, which did nearly exactly what I wanted. I took that and hacked it up so my settings were all hard coded, added a she-bang, made it executable and linked to it from somewhere in my path. Now I can simply type “wakebold” and it will wake up my desktop at home (whom have affectionally named “bold”).</p>
<p>My changes were really easy:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Configure the IP and MAC address for the computer you want here:
SETTINGS = { :mac_addr => "00:00:00:00:00:00", :host_name => "example.homeip.net"}
if $0 == __FILE__
wol=WakeOnLan.new
wol.wake(SETTINGS[:mac_addr], "255.255.255.255", SETTINGS[:host_name])
wol.close
puts "Waking up #{SETTINGS[:host_name]}"
end
</code></pre></div></div>
<p>My hacked version can be found in my <a href="http://www.fuzzymonk.com/svn/wakeywakey">svn repo</a>.</p>
<p>To do all this, you can do the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>svn co http://www.fuzzymonk.com/svn/wakeywakey
chmod +x wakeywakey/wakey.rb
ln -s wakeywakey/wakey.rb /usr/local/bin/wakebold # or elsewhere in your path
</code></pre></div></div>
The next post will be better.2008-06-01T00:00:00+00:00http://www.codeography.com/2008/06/01/the-next-post-will-be-better<p>I’ve been out in Oregon at RailsConf. As you might have noticed from twitter, I’ve been here three days now. The Conference has been outstanding, and the people here make up one of the coolest communities I have ever been exposed too. The problem with the first few days out here was the happening going on back home. Three things really sucked the joy out of this otherwise awesome geektopia, a client at work who thinks fire alarms are the proper way to do business, getting my credit card number stolen, and the programming contest at work.</p>
<p>Lets touch on these in reverse order. The contest was optional, but I have a teammate who worked very hard and I was not about to leave him hanging. Unfortunately I was out of town (here, in OR) when they were presenting the projects in the office. To handle this I created a screen cast. Which is not the quickest or easiest thing in the world to do. I quickly got a copy of QuickTime Pro and iShowU and threw something together. A few tries through and I was pretty happy. Figured one more try and I’d be set. But nothing worked that time, it was 4 AM my time, and I had a decent run. So I uploaded it and crashed. It was just time to be done with that.</p>
<p>It sucks to get your CC stolen. If the thief reads my blog: I canceled the account. And you are a mean jerk.</p>
<p>The fire alarm as a development methodology is really starting to wear me out. I had been running strong with with the “my project, my baby” feeling, but as I have been reminded it isn’t. Which really removes the desire to meet the–artificial–deadlines at all cost. I still want to succeed, but it is hard when the people who are helping you don’t help. Sorta like the curly haired helper, but not cute nor do they give out hugs so happily.</p>
<p>I am just burnt out on the project, and need something fresh. Or a vacation. Or a few weeks paternity leave.</p>
<p>OK, a much happier post on the way, stay tuned.</p>
Bash + Rake +2008-03-23T00:00:00+00:00http://www.codeography.com/2008/03/23/bash-rake<p>i wanted tab completion for rake tasks with bash on OS X, so…</p>
<p>I Installed the gem:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gem install rake-command-completion
</code></pre></div></div>
<p>Then I added this to .bash_login (or .bashrc)</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>complete -C /usr/local/bin/command_completion_for_rake -o default rake
</code></pre></div></div>
Added a Trac-Hack2008-03-07T00:00:00+00:00http://www.codeography.com/2008/03/07/added-a-trac-hack<p><img src="http://photos.fuzzymonk.com/blog/image/595/RistoInk1-766603.png" border="0" class="picture" /></p>
<p>I heart trac, and I also heart VibrantInk, as well as my VibrantInk-based color scheme for Vim and Visual Studio.</p>
<p>Earlier this week I spent a little time making a few tweaks to the css of Trac, and was able to get the code browser to show up in my beloved color scheme. After walking around all proud of my self, but everyone I told was more or less utterly unimpressed. So I decided to do the selfless thing and brag about it to the Trac community. Thus the <a href="http://trac-hacks.org/wiki/VibrantInkCodeTheme">VibrantInkCodeTheme</a> was born.</p>
<p>My visual studio scheme is form John Lam’s settings with a few minor tweaks</p>
<p>My vim scheme is based the VividChalk theme by Tim Pope. I’ve done a fair amount of work on this one, making it work under gVim, Windows CMD, gnome-terminal and the Mac Terminal. The tri-platform thing was a bit of a pain. Every time i got it just right under two of the three, it would break on the third. Seriously, you’d think in the year 2008 we could get at least 256 colors in *all* the terminals.</p>
Focused rails tests in vim!2008-02-12T00:00:00+00:00http://www.codeography.com/2008/02/12/focused-rails-tests-in-vim<p><a href="http://rails.vim.tpope.net/">Rails.vim</a> allows you to run focused tests (ala TextMate) buy placing the cursor in the method and running :Rake.</p>
<p>This is teh coolness.</p>
Vim on Vista2007-11-22T00:00:00+00:00http://www.codeography.com/2007/11/22/vim-on-vista<p>Ok, so I wasted a good part of thanksgiving day trying to get vim workign again on vista. I am not sure what happened, but it went nuts. It may have been the recent windows updates or the face that I in stalled .NET 3.5, but it was unusable. None of the plugins/syntax highlighting/menus that I have grown to love. So here is what I did:</p>
<p>Vim on Vista</p>
<p>Installed gvim71-2.exe to C:\vim (<a href="http://hasno.info/2007/5/18/windows-vim-7-1-2">from here</a>)</p>
<p>Copy the folling files into C:\vim\vim71\</p>
<ul>
<li>iconv.dll (<a href="http://sourceforge.net/projects/gettext">from here</a> You can find the dll file in the bin directory of the “libiconv-win32” archive.)</li>
<li>libintl.dll (<a href="http://sourceforge.net/projects/gettext">from here</a> Get “intl.dll” from the bin directory in the gettext-win32 archive and store it as “libintl.dll” in the same directory as gvim.exe, overwriting the file that may already be there.)</li>
<li>gvimext.dll (<a href="http://www.vim.org/scripts/script.php?script_id=1720">from here</a>)</li>
</ul>
<p>Here is the thing that stuck me for hours, if you had previously installed vim</p>
<p>to the recommended location of C:\Program Files you won’t be able to associate</p>
<p>files with the new location until you edit the registry. Go to:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HKEY_CLASSES_ROOT\Applications\gvim.exe
</code></pre></div></div>
<p>Make sure the edit\command and open\command Keys have the following default value:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\vim\vim71\gvim.exe "%1"
</code></pre></div></div>
<p>If you want the “Edit with vim” in windows explorer:</p>
<ul>
<li>Run C:\vim\vim71\install.exe</li>
<li>Choose no when asked if you want to uninstall, then enter “d 14”If you get a gvim not in your path error with the “Edit with vim” shell ext, make sure you don’t have gvim.exe set to run as Administrator, as that will break it.</li>
</ul>
<p>If you don’t want to run around and get those files, you can download them <a href="http://www.blogger.com/files/vimvista.zip">here</a>.</p>
<p>Also, I added my suite of vim files <a href="http://www.blogger.com/files/vimfiles.zip">here</a>.</p>