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

<channel>
	<title>Andrew Brookins</title>
	<atom:link href="http://andrewbrookins.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://andrewbrookins.com</link>
	<description></description>
	<lastBuildDate>Sun, 20 May 2012 06:12:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Go: How to Get the Directory of the Current File</title>
		<link>http://andrewbrookins.com/tech/golang-get-directory-of-the-current-file/</link>
		<comments>http://andrewbrookins.com/tech/golang-get-directory-of-the-current-file/#comments</comments>
		<pubDate>Sat, 19 May 2012 22:10:38 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=831</guid>
		<description><![CDATA[In Python I often use the __file__ constant to get the directory of the current file (e.g., os.path.dirname(os.path.realpath(__file__))). While writing a Go app recently, I found that there wasn&#8217;t an immediately obvious (or searchable, even with &#8220;golang&#8221;) equivalent. But in the annals of the golong-nuts mailing list I eventually found out about runtime.Caller(). This returns [...]]]></description>
			<content:encoded><![CDATA[<p>In Python I often use the <code>__file__</code> constant to get the directory of the current file (e.g., <code>os.path.dirname(os.path.realpath(__file__))</code>). While writing a Go app recently, I found that there wasn&#8217;t an immediately obvious (or searchable, even with &#8220;golang&#8221;) equivalent.</p>
<p>But in the annals of the golong-nuts mailing list I eventually found out about <code>runtime.Caller()</code>. This returns a few details about the current goroutine&#8217;s stack, including the file path.</p>
<p>The context of my problem was opening a data file in a shared package. What I cooked up was:</p>
<p><script src="https://gist.github.com/2732551.js?file=gistfile1.go"></script></p>
<p>Sending <code>1</code> to <code>runtime.Caller</code> identifies the caller of <code>runtime.Caller</code> as the stack frame to return details about. So you you get info about the file your method is in. Check <a href="http://golang.org/pkg/runtime/#Caller">the docs</a> for more in-depth coverage.</p>
<p>It&#8217;s not quite as elegant as <code>__file__</code> but it works.</p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/golang-get-directory-of-the-current-file/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Run Django Unit Tests in a Sublime Text 2 Build System</title>
		<link>http://andrewbrookins.com/tech/run-django-unit-tests-in-a-sublime-text-2-build-system/</link>
		<comments>http://andrewbrookins.com/tech/run-django-unit-tests-in-a-sublime-text-2-build-system/#comments</comments>
		<pubDate>Tue, 28 Feb 2012 17:11:20 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=820</guid>
		<description><![CDATA[With the dev builds of Sublime Text 2, you can easily set up a build system that runs Django unit tests. You do this by adding a build system to your Sublime Text 2 project file for the Django project. I&#8217;ll include an example project file in this post that runs manage.py test --noinput as [...]]]></description>
			<content:encoded><![CDATA[<p>With the dev builds of Sublime Text 2, you can easily set up a build system that runs Django unit tests. You do this by adding a build system to your Sublime Text 2 project file for the Django project.</p>
<p>I&#8217;ll include an example project file in this post that runs <code>manage.py test --noinput</code> as the build command. In order for this to work with the current implementation of build systems, the project file must add the Django project dir and the virtualenv&#8217;s site-packages directory to the <code>PYTHONPATH</code>.</p>
<p>Note a couple of things:</p>
<ul>
<li>In the project file, ${project_path} refers to the directory in which the project file exists: I created mine in the virtual env directory (the directory with the bin/ and lib/ directores for the virtualenv). For more info on other possible substitutions see <a href="http://sublimetext.info/docs/en/reference/build_systems.html">the docs</a> (note that I couldn&#8217;t get substitutions to work in the &#8220;env&#8221; dictionary)</li>
<li>My placeholder text <code>django_project_dir</code> stands for the directory that contains your Django project files inside of the virtualenv</li>
<li>This doesn&#8217;t use the <code>python</code> binary in your virtualenv &#8212; so your mileage may vary </li>
</ul>
<p>One final thing to note is that I&#8217;ve added the <code>lib/python2.7</code> directory as a folder in the project file. This is not related to the build system. It simply includes libraries in my &#8220;Find in File&#8230;&#8221; searches, allowing me to easily search for, e.g., Django classes and usages alongside my own. (SublimeRope is also a helpful tool for exploring.)</p>
<p>Anyway, here is the example project file:</p>
<p><script src="https://gist.github.com/1933635.js?file=gistfile1.json"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/run-django-unit-tests-in-a-sublime-text-2-build-system/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python: How to tell what class a decorated method is in at runtime</title>
		<link>http://andrewbrookins.com/tech/how-to-get-the-name-of-the-class-of-a-decorated-method-in-python/</link>
		<comments>http://andrewbrookins.com/tech/how-to-get-the-name-of-the-class-of-a-decorated-method-in-python/#comments</comments>
		<pubDate>Wed, 22 Feb 2012 21:01:23 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=808</guid>
		<description><![CDATA[When profiling a Python app, it&#8217;s helpful to have a decorator that wraps functions and reports details about their performance. Assuming you are doing this to report some metric about the function, you&#8217;ll want the decorator to work with both bound and unbound functions (IE, regular functions and methods of a class), and if the [...]]]></description>
			<content:encoded><![CDATA[<p>When profiling a Python app, it&#8217;s helpful to have a decorator that wraps functions and reports details about their performance. Assuming you are doing this to report some metric about the function, you&#8217;ll want the decorator to work with both bound and unbound functions (IE, regular functions and methods of a class), and if the decorator wraps a method, you&#8217;ll probably want to know the name of the class the method belongs to.</p>
<p>There is only one way (<em>update</em>: two ways) I&#8217;ve found to do this. They both involve the <code>inspect</code> module. (There are obvious ways to do it that don&#8217;t work with decorators.)</p>
<p>You can&#8217;t assume that the first argument in a function always refers to its class because that would break in the case that the function was not a method. However, the strong convention in Python is to name the first argument of methods &#8216;self&#8217;. Relying on this convention, we can easily tell if a function includes such an argument with the <code>inspect</code> module.</p>
<p>The <code>inspect</code> module&#8217;s <code>getcallargs</code> function will map the parameter names from a function&#8217;s signature to its arguments. Given a function <code>fn</code> that your decorator wraps, you can call <code>inspect.getcallargs(fn, *args)</code> at runtime and discover that the first positional argument is the &#8216;self&#8217; parameter defined in the method&#8217;s signature!</p>
<p>Now, the use of &#8216;self&#8217; is such a strong Pythonic convention that it&#8217;s good enough in most cases to use the presence of such a parameter in a function to know that it&#8217;s a bound function (again, a class method), and you can then inspect the &#8216;self&#8217; argument for its class using <code>__class__.__name__</code>.</p>
<p>Here is an example decorator that will print out the class name of a decorated bound function:</p>
<p><script src="https://gist.github.com/1887230.js?file=gistfile1.py"></script></p>
<p><em>Update</em>: In Python 2.6, which does not include <code>inspect.getcallargs</code>, you can use <code>inspect.getargspec</code> to similar effect:</p>
<p><script src="https://gist.github.com/1893856.js?file=gistfile1.py"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/how-to-get-the-name-of-the-class-of-a-decorated-method-in-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Make Sublime Text 2 More like Vim: Wrap Code, Go To Last Edit, Jump Back, and More</title>
		<link>http://andrewbrookins.com/tech/make-sublime-text-2-more-like-vim-wrap-code-goto-last-edit-and-more/</link>
		<comments>http://andrewbrookins.com/tech/make-sublime-text-2-more-like-vim-wrap-code-goto-last-edit-and-more/#comments</comments>
		<pubDate>Thu, 19 Jan 2012 14:16:46 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=776</guid>
		<description><![CDATA[I&#8217;ve been trying out Sublime Text 2 as a replacement for Vim. While I enjoy using it and I experienced the &#8220;Wow, this does 90% of what Vim does&#8221; moment, I kept a running list of all the features in the remaining 10% that I relied on every day. These included: Better code wrapping (gq) [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been trying out Sublime Text 2 as a replacement for Vim. While I enjoy using it and I experienced the &#8220;Wow, this does 90% of what Vim does&#8221; moment, I kept a running list of all the features in the remaining 10% that I relied on every day.</p>
<p>These included:</p>
<ul>
<li>Better code wrapping (<code>gq</code>)</li>
<li>Go to last edit (<code>''</code>)</li>
<li>Go to file in Ack search output</li>
<li>Display full path to current file (<code>:echo expand('%:p')&lt;CR&gt;</code>)</li>
<li>Jumping back and forward through files</li>
</ul>
<p>However, Sublime Text 2 has a great Python API and I was able to whip up plugins for these tasks that perform just as well as in Vim. <em>Update</em>: I also found the navigationHistory plugin, which does a pretty good job of back/forward jumps.</p>
<h2>Better code wrapping</h2>
<p>Vim&#8217;s reformat text command (<code>gq</code>) can take multiple paragraphs and text in comments and flow them to the current textwidth setting. Some people don&#8217;t care about this, but I prefer to keep lines of code less than 80 characters wide, so I can open multiple files side-by-side. (Also, Pep-8.)</p>
<p>Sublime Text 2 had a &#8220;wrap&#8221; feature, but it failed to intelligently wrap comments, it joined separate paragraphs together and it wouldn&#8217;t reflow selected text (only the paragraph around the cursor).</p>
<p>The plugin I wrote creates a Wrap Code command (mapped to <code>gq</code> in Vintage mode) that works reasonably on commented lines of code (and uncommented lines), multiple paragraphs and selected text, thanks to the <code>codewrap.py</code> module written by Nir Soffer.</p>
<p><a href="https://github.com/abrookins/WrapCode">Download the WrapCode plugin on Github.</a></p>
<h2>Go to the last edit</h2>
<p>I&#8217;m used to typing <code>'.</code> in a buffer in Vim to move the cursor to the last edit. Great feature. Totally underrated.</p>
<p>If you use Vintage mode in Sublime Text 2, you&#8217;ll quickly discover that this command does nothing &#8212; worse than nothing, in fact, as it seems to refocus your cursor somewhere other than the text of the buffer, forcing you to use your mouse to recover.</p>
<p>While I couldn&#8217;t bind my plugin to the <code>'.</code> command without forking Vintage mode, I bound it to <code>Super+'</code> and it works the same as Vim&#8217;s.</p>
<p><a href="https://github.com/abrookins/GotoLastEdit">Download the GotoLastEdit plugin on Github.</a></p>
<h2>Easily open search results</h2>
<p>Another thing I missed about Vim was its Ack plugin. The &#8220;Find in Files&#8221; feature of Sublime Text 2 is great, but it didn&#8217;t provide an easy way to quickly open a file listed in the search results via the keyboard (you can double-click on a line to open it, though).</p>
<p>So I wrote a plugin that, in a Search Results window, allows you to do one of the following via the keyboard:</p>
<ul>
<li>On a &#8220;matched&#8221; line in the search output, open its file at the line of the match</li>
<li>On a file path in the search output (without a line number), open the file in a new tab</li>
</ul>
<p><a href="https://github.com/abrookins/OpenSearchResult">Download the OpenSearchResult plugin on Github.</a></p>
<h2>Display full path to file in status bar</h2>
<p>I use Vim in OS X&#8217;s full screen mode, with no tabs or status line. Working this way, I don&#8217;t have reference to the path of the current file. Of course, I know the name of the file because I usually typed it, but sometimes the full path is important; e.g., if I have two Mercurial branches of the same code in different directories.</p>
<p>So, I have a command mapped to <code>,F</code> that displays the full path. Then it silently goes away after a moment. I love that command.</p>
<p>I couldn&#8217;t find an ideal way to implement this in Sublime Text 2, other than to create a command that would toggle displaying the path to the current file in the status bar. It works well enough for me, however.</p>
<p><a href="https://github.com/abrookins/FilenameStatus">Download the FilenameStatus plugin on Github.</a></p>
<h2>Jumping back and forward</h2>
<p>One of Vim&#8217;s most awesome features is Control-O/Control-I to jump back and forward &#8212; maybe I can generalize to say that <em>all</em> of Vim&#8217;s jump commands are part of its &#8220;killer app&#8221; status.</p>
<p>Sublime Text 2 doesn&#8217;t have a feature like this, but someone on the internet has packaged a version of Martin Aspelli&#8217;s <code>navigationHistory</code> plugin, which comes close.</p>
<p><a href="https://github.com/marram/sublime-navigation-history">Download the navigationHistory plugin on Github.</a></p>
<h2>Installing the plugins</h2>
<p>You install these plugins the same way as other Sublime Text 2 plugins, by downloading the files and dropping them into the Packages directory.</p>
<p>See <a href="http://sublimetext.info/docs/en/extensibility/plugins.html">this documentation</a> for more details if you need additional help installing plugins.</p>
<p>The default key bindings are intended for Vintage mode and are oriented for OS X.</p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/make-sublime-text-2-more-like-vim-wrap-code-goto-last-edit-and-more/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sharp Edges: Protecting Ourselves from Digital Publishing</title>
		<link>http://andrewbrookins.com/tech/sharp-edges-protecting-ourselves-from-digital-publishing/</link>
		<comments>http://andrewbrookins.com/tech/sharp-edges-protecting-ourselves-from-digital-publishing/#comments</comments>
		<pubDate>Sat, 07 Jan 2012 19:42:11 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[books]]></category>
		<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=731</guid>
		<description><![CDATA[Nicholas Carr wrote in a recent article that he considered the ability of publishers to change text after they had released it &#8220;insidious&#8221; and a &#8220;bane&#8221; of digital publishing &#8212; specifically, if such changes are made in response to market research. I agree that there is a challenge inherent in the new ease with which [...]]]></description>
			<content:encoded><![CDATA[<p>Nicholas Carr wrote in a recent article that he considered the ability of publishers to change text after they had released it &#8220;insidious&#8221; and a &#8220;bane&#8221; of digital publishing &#8212; specifically, if such changes are made in response to market research.</p>
<p>I agree that there is a challenge inherent in the new ease with which publishers may release versions of a text, but the challenge I see is different than the one Carr suggested. Data about the chapters that readers skip and areas that cause people to abandon their reading will only help publishers create better, more relevant content, just as this data has helped web site authors do the same. It is our response, as readers, to the possibility of frequent (and silent) revisions to text that I worry about.</p>
<h2>Movable Text</h2>
<p>As a summary of the key difference between print and electronic publishing, Carr described electronic publishing as having replaced Gutenberg&#8217;s movable type with &#8220;movable text.&#8221; For centuries, once set and printed, the text of a book remained the same. Today, with web sites and now ebooks, publishers may change the text at any time, introducing multiple divergent copies or, if the distribution method supports it, even changing the copy you are reading as you read it.</p>
<p>Carr wrote about the downside of this change that,</p>
<blockquote><p>The promise of stronger sales and profits will make it hard to resist tinkering with a book … adding a few choice words here, trimming a chapter there, maybe giving a key character a quick makeover.</p></blockquote>
<p>&#8211; <a href="http://online.wsj.com/article/SB10001424052970203893404577098343417771160.html" target="_blank">Books That Are Never Done Being Written</a></p>
<p>What is wrong with this? While some readers may finish every book they start, I have dismissed dozens of books in my life, at various points in their stories, after having read one too many missteps of voice or plot, or simply because I was bored. Life is short. There are more books to read than I have time for. So why should I read a poorly written book, and what do I care for the &#8220;shape&#8221; of a book (to quote Carr quoting Updike) if I can&#8217;t connect with it?</p>
<p>Creators and publishers who release work on the internet can get faster and more in-depth feedback from consumers than in traditional publishing &#8212; not just through comments but through analytics about a reader&#8217;s behavior. Analytics can show what people look for in a text and different ways they respond (e.g., most people stopped reading on page two). As anyone who has written a blog or maintained a web site will know, this information is extremely valuable as way of testing what people want to read and what they don&#8217;t.</p>
<p>The same will now be true for books. As readers, our reactions to books, not just the fact that we purchased them but more intimate details like how long we lingered on a page and where we stopped reading (if it wasn&#8217;t the end), will place us in tighter feedback loops with authors. How is this a &#8220;bane&#8221;?</p>
<h2>Authentic Text</h2>
<p>What <em>is</em> wrong with this model is that we must change our idea of the persistence and security of human knowledge to fit it. We have to create new mechanisms to ensure the authenticity of texts. There are measures we can take to accomplish this:</p>
<ul>
<li>Creators should have control over changes made to their works, to protect themselves from publishers introducing alterations based on sales data.</li>
<li>Readers should have access to all released versions of a text. Each authorized edition of a text should have its own ID that is registered with a trusted authority. And if the publisher releases a new version of a book that is already on our ebook readers, we ought to have the right to approve whether or not we update to it.</li>
<li>A trusted organization of the public good should house a copy of each version of released texts, to reduce the chance that individuals, companies and governments can alter or destroy the source files.</li>
</ul>
<p>In the traditional publishing model, a printed edition of a work with an ISBN is a &#8220;known good&#8221; source copy. It is authorized by someone. Multiple editions of a book may exist, but as readers and historians we can examine our authorized copies of these editions. We can protect them.</p>
<p>As we move toward using and relying on digital text, we must develop new means of protecting the authenticity of this information. The bane &#8212; the sharp edge &#8212; of &#8220;movable text&#8221; is not the ease with which we may change our books after we publish them. It is that our mechanisms for protecting ourselves from such change are outdated.</p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/sharp-edges-protecting-ourselves-from-digital-publishing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iA Writer and Notational Velocity</title>
		<link>http://andrewbrookins.com/tech/ia-writer-and-notational-velocity/</link>
		<comments>http://andrewbrookins.com/tech/ia-writer-and-notational-velocity/#comments</comments>
		<pubDate>Sat, 31 Dec 2011 22:03:48 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=675</guid>
		<description><![CDATA[The OS X apps iA Writer and Notational Velocity are great for writing and taking notes, respectively. I wanted to try using them together, by setting iA Writer as the external editor for Notational Velocity, but after doing so I noticed that iA Writer would not open with the keyboard shortcut (Command-Shift-E), and it was [...]]]></description>
			<content:encoded><![CDATA[<p>The OS X apps <a href="http://iawriter.com">iA Writer</a> and <a href="http://notational.net">Notational Velocity</a> are great for writing and taking notes, respectively.</p>
<p>I wanted to try using them together, by setting iA Writer as the external editor for Notational Velocity, but after doing so I noticed that iA Writer would not open with the keyboard shortcut (Command-Shift-E), and it was grayed out in the &#8216;Note->Edit With&#8217; menu.</p>
<p>After tinkering, I found that Notational Velocity&#8217;s note storage must be set to plaintext files and the file extension must be &#8216;.txt&#8217; (or &#8216;.md&#8217;, which is iA Writer&#8217;s default file extension). The rest of this guide will assume you want to use &#8216;.txt&#8217; as the file extension for notes.</p>
<h2>Full Requirements</h2>
<p>So, the full requirements to use iA Writer with Notational Velocity are:</p>
<ul>
<li>Set iA Writer as the External Editor in Notational Velocity</li>
<li>Use plaintext file storage for notes in Notational Velocity</li>
<li>Use the &#8216;.txt&#8217; extension for note files</li>
</ul>
<h2>Set iA Writer as the External Editor</h2>
<ul>
<li>Open Notational Velocity&#8217;s preferences</li>
<li>Click &#8216;General&#8217;</li>
<li>Choose &#8216;iA Writer&#8217; in the External Editor drop-down</li>
</ul>
<h2>Use Plain Text Storage for Notes</h2>
<ul>
<li>Open Notational Velocity&#8217;s preferences</li>
<li>Click &#8216;Notes&#8217;</li>
<li>Click &#8216;Storage&#8217;</li>
<li>Choose a folder to save and read notes from in the &#8216;Read notes from folder&#8217; drop-down (I suggest a <a href="http://dropbox.com">Dropbox</a> folder)</li>
<li>Choose &#8216;Plain Text Files&#8217; in the &#8216;Store and read notes as:&#8217; drop-down</li>
<li>Highlight &#8216;txt&#8217; in the Extension list and click the check-box to make it the default extension</li>
</ul>
<h2>Changing Existing File Extensions</h2>
<p>If iA Writer is still grayed out in the &#8216;Note -> Edit With&#8217; menu or fails to respond to the external editor keyboard shortcut, make sure that the notes you are editing have the &#8216;.txt&#8217; extension.</p>
<p>All of your notes should now be stored as individual files in the folder you chose in Notational Velocity&#8217;s preferences. To change the extension on these files, open that folder in Terminal or Finder and rename the files so that they end with &#8216;.txt&#8217;.</p>
<h2>Batch Renaming Files in Terminal</h2>
<p>If you have tons of notes and need to change all of them to a new extension, open Terminal and <code>cd</code> to the folder you chose for note storage in Notational Velocity. Then run the following command (assuming the original extension of the files was &#8216;.wiki&#8217;, which it was in my case):</p>
<pre><code>    for old in *.wiki; do mv "$old" "`basename $old .wiki`.txt"; done
</code></pre>
<h2>Done… Bonus Round?</h2>
<p>You should be set now.</p>
<p>However, iA Writer uses the Markdown format, so as an extra bonus you could add a Markdown plugin to Vim, allowing you to easily edit the same text files in Notational Velocity, iA Writer and Vim, which is of course the greatest text editor of all time.</p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/ia-writer-and-notational-velocity/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Fix Slow Scrolling in Vim and MacVim on OS X</title>
		<link>http://andrewbrookins.com/tech/slow-scrolling-in-vim-and-macvim-on-os-x-increase-key-repeat-settings/</link>
		<comments>http://andrewbrookins.com/tech/slow-scrolling-in-vim-and-macvim-on-os-x-increase-key-repeat-settings/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 15:08:30 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=626</guid>
		<description><![CDATA[I finally discovered the cause of my #1 OS X problem: slow scrolling in Vim, both in Terminal.app and in MacVim. There was always a marked difference between Vim on my Mac and Vim on Linux. Scrolling with the movement keys (j/k in particular) was blindingly fast on Linux, but plodded along on my Mac so [...]]]></description>
			<content:encoded><![CDATA[<p>I finally discovered the cause of my #1 OS X problem: slow scrolling in Vim, both in Terminal.app and in MacVim.</p>
<p>There was always a marked difference between Vim on my Mac and Vim on Linux. Scrolling with the movement keys (j/k in particular) was blindingly fast on Linux, but plodded along on my Mac so slowly that I began using Control-F and Control-B most of the time.</p>
<p>It turns out there was a simple cause for the problem: key repeat settings. The setting was too low for me.</p>
<p>You can change Key Repeat settings in System Preferences -&gt; Keyboard. Tweak the Key Repeat and Delay Until Repeat settings to find a good speed. I had to restart after changing these settings to see any effect.</p>
<p>Now, the vanilla options helped some, but in order to get <em>really</em> fast scrolling speed, I had to take two more steps:</p>
<ul>
<li>Switch to <a href="http://www.iterm2.com/">iTerm 2</a> for my terminal. Terminal.app, even Lion&#8217;s, couldn&#8217;t cope with faster key repeat settings &#8211; Vim was still slow, though a bit faster.</li>
<li>Tweak the repeat values even more with <a href="http://pqrs.org/macosx/keyremap4macbook/">KeyRemap4MacBook</a>.</li>
</ul>
<p>The magic KeyRemap4MacBook values for me were:</p>
<ul>
<li>[Key Repeat] Initial Wait: <strong>15 (Update: 500)</strong></li>
<li>[Key Repeat] Wait: <strong>35</strong></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/slow-scrolling-in-vim-and-macvim-on-os-x-increase-key-repeat-settings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Instant Django Dev Environments with Tmux, Tmuxinator, and Virtualenvwrapper</title>
		<link>http://andrewbrookins.com/tech/instant-django-dev-environments-with-tmux-tmuxinator-and-virtualenvwrapper/</link>
		<comments>http://andrewbrookins.com/tech/instant-django-dev-environments-with-tmux-tmuxinator-and-virtualenvwrapper/#comments</comments>
		<pubDate>Sun, 09 Oct 2011 15:19:35 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[technology]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=440</guid>
		<description><![CDATA[This post describes how to use a few common tools to instantly set up and tear down Django development environments. I&#8217;ve found that such automation is most useful when switching between branches in source control. Without automation, you have to manually kill and reconstruct any Django shell and development server instances for each branch (and [...]]]></description>
			<content:encoded><![CDATA[<p>This post describes how to use a few common tools to instantly set up and tear down Django development environments.</p>
<p>I&#8217;ve found that such automation is most useful when switching between branches in source control. Without automation, you have to manually kill and reconstruct any Django shell and development server instances for each branch (and sometimes the database shell, too).</p>
<p>While my examples are geared toward Django development, the approach I describe works equally well with Rails and other frameworks.</p>
<p>Tools used:</p>
<ul>
<li>Tmux, a terminal multiplexer like GNU Screen</li>
<li>Tmuxinator, a nice Ruby gem for automating Tmux</li>
<li>Virtualenv, a tool for creating isolated Python environments</li>
<li>Virtualenvwrapper, a set of extensions to virtualenv</li>
<li>My <a href="https://github.com/abrookins/dotfiles/blob/master/.tmux.conf" target="_blank">tmux.conf</a></li>
</ul>
<p>By the end of this post, you will have a new command available in your terminal that will create a Tmux session with multiple views into your Django project.</p>
<h2>Why Tmux?</h2>
<p>First, a quick note about Tmux.</p>
<p>Until earlier this year, I had used GNU Screen for managing persistent terminal sessions. It worked well. However, I grew dissatisfied with the pace of development in the project, the lack of new features, and the inconsistent availability of vertical splits across different platforms. So, I tried Tmux, and I haven&#8217;t gone back.</p>
<p>If you are a Screen user, then I suggest you try Tmux, but you can probably achieve a similar method to the one described in this post using Screen and one of the automation scripts designed to work with it.</p>
<h2>Virtualenv and Virtualenvwrapper</h2>
<p>My example uses virtualenv and virtualenvwrapper. Note that you do not need to use either of those tools to set up or tear down a Django development environment with Tmux. They just make working with multiple Python projects easier.</p>
<p>If you don&#8217;t use these tools, remove the <code>venvwrapper &amp;&amp; workon my_project</code> portion of the examples.</p>
<p>I will skip explaining how to install those tools or use them, since many tutorials on those subjects exist already, in addition to the <a href="http://www.virtualenv.org/en/latest/" target="_blank">virtualenv docs</a> and <a href="http://www.doughellmann.com/docs/virtualenvwrapper/" target="_blank">virtualenvwrapper docs</a>.</p>
<p>After this point I will assume you have created a virtualenv for your Python code in a directory named <code>my_project</code> and have configured virtualenvwrapper so that you can execute <code>workon my_project</code> to activate the virtualenv.</p>
<h2>Install Tmux and Tmuxinator</h2>
<p>Install Tmux with your package management software of choice. It&#8217;s available in apt-get, MacPorts, etc.</p>
<p>Next, install Tmuxinator (instructions <a href="https://github.com/aziz/tmuxinator" target="_blank">here</a>).</p>
<p>As a side note, I recommend using <a href="https://rvm.beginrescueend.com/">RVM</a> to manage your Ruby versions.</p>
<h2>Create a Project File</h2>
<p>Before taking this step, make sure you&#8217;ve followed the Tmuxinator installation instructions and have exported your EDITOR shell variable, e.g.:</p>
<pre>$ export EDITOR=vim</pre>
<p>Now, use Tmuxinator to create a &#8220;project file&#8221; (a YAML file containing shorthand configuration settings for Tmux).</p>
<pre>$ tmuxinator new my_project</pre>
<p>A file should now open in your text editor. The Tmuxinator docs use a Rails-inspired example. The following is a Django example in which I create a Tmux session with multiple windows (an explanation follows the example).</p>
<h2>A Django Example</h2>
<pre># ~/.tmuxinator/my_project.yml
# you can make as many tabs as you wish...

project_name: my_project
project_root: ~/
tabs:
  - zsh: ls -l
  - shell: venvwrapper &amp;&amp; workon my_project &amp;&amp; cd my_project &amp;&amp;  ./manage.py shell
  - database: venvwrapper &amp;&amp; workon my_project &amp;&amp; cd my_project &amp;&amp; ./manage.py dbshell
  - server: venvwrapper &amp;&amp; workon my_project &amp;&amp; cd my_project &amp;&amp; ./manage.py runserver
  - logs:
      layout: even-horizonal
      panes:
        - tail -f /opt/local/var/log/nginx/access.log
        - tail -f /opt/local/var/log/nginx/error.log
        - sudo python -m smtpd -n -c DebuggingServer localhost:25</pre>
<h2>Explanation of the Example</h2>
<p>The example creates a Tmuxinator project file named <code>my_project.yml</code>, which generates a <code>my_project.tmux</code> file and creates the command <code>start_my_project</code> that you can use to start the Tmux session.</p>
<p>The example assumes that a virtualenv exists in a directory named <code>my_project</code> and the env directory contains a directory named <code>my_project</code> (e.g., in my case, <code>~/envs/my_project/my_project</code>). Obviously, this should match whatever directory structure you actually use for your virtualenvs.</p>
<p>The Tmuxinator docs describe everything that you may configure with a project file. There are more options available than the ones in my example, but I use this relatively simple configuration for my day-to-day Django work, and it saves a bunch of time.</p>
<p>Here is an explanation of the options the example uses:</p>
<ul>
<li><strong>project_name</strong>: the name of the project; this becomes part of the command you use to launch a Tmux session, e.g., <code>start_my_project</code></li>
<li><strong>project_root</strong>: the starting directory for each command that you tell Tmuxinator to execute</li>
<li><strong>tabs</strong>: each item in this list represents a named &#8220;tab&#8221; or Tmux window in which one or more shell sessions will run</li>
<li><strong>zsh</strong>: I like to have a shell opened and pointed at my home directory for random commands</li>
<li><strong>shell</strong>: activate the virtualenv and load the Django shell for my project</li>
<li><strong>database</strong>: activate the virtualenv and load the database shell for my project</li>
<li><strong>server</strong>: activate the virtualenv and start the Django development server for my project</li>
<li><strong>logs</strong>: create a three-pane split using Tmux&#8217;s <code>even-horizontal</code> layout (each pane is an even height) to display logging output from nginx, which is running my dev machine and proxying requests to the Django dev server, and a Python SMTP debugging server (because I like to see HTML/text dumps of emails generated during development)</li>
</ul>
<p>Now, assuming you followed the Tmuxinator docs and have the following line in your zshrc/bashrc (&#8230;):</p>
<pre># Tmuxinator
[[ -s $HOME/.tmuxinator/scripts/tmuxinator ]] &amp;&amp; source $HOME/.tmuxinator/scripts/tmuxinator</pre>
<p>&#8230; You can run <code>start_my_project</code> from your shell of choice to open a Tmux session with all the tabs you configured.</p>
<h2>Making this Really Useful</h2>
<p>Instantly summoning a development environment is great, but where this approach really shines is when you need to switch branches in your project.</p>
<p>In a single day, I might work on two or three different branches in one project. Before using Tmux and Tmuxinator, I would have to constantly kill and restart various commands each time I switched to a different branch. Now I just do the following:</p>
<ul>
<li>Issue the <code>kill-session</code> command within a loaded Tmux session (<code>Ctrl-b : kill-session &lt;CR&gt;</code>)</li>
<li>Back at the shell, run my <code>start_project</code> command again</li>
</ul>
<p>Two commands to restart an entire session from the new branch. Handy! And, if you have other sessions loaded, <code>kill-session</code> preserves them by killing only the session you are currently in (<code>kill-server</code> kills all sessions).</p>
<h2>Summary, Other Resources</h2>
<p>Tmux is great, and automating session creation has saved me a lot of time. I hope it saves you a few precious minutes (hours?!), too.</p>
<p>If you&#8217;re a Screen user who has read this far, I encourage you to try out a similar approach with <a href="https://github.com/jondruse/screeninator" target="_blank">Screeninator</a>. Of, if you just want to get some tabs up in your terminal app, try <a href="https://github.com/achiu/terminitor" target="_blank">Terminitor</a>.</p>
<h2>Addendum: Multiple Sessions</h2>
<p>One thing I love about Tmux is that you can have multiple sessions open. So, for example, while I&#8217;m working I usually have two sessions open: my Django project session and a session for system administration that has my Chef repository (using <a href="https://github.com/tobami/littlechef" target="_blank">LittleChef</a>) and a few SSH tabs open:</p>
<pre># ~/.tmuxinator/work.yml
# you can make as many tabs as you wish...

project_name: work
project_root: ~/
tabs:
  - zsh: ls -l
  - chef: venvwrapper &amp;&amp; workon kitchen
  - qa: ssh username@my_qa_server
  - prod: ssh username@my_prod_web_server
  - (several more ssh sessions here)</pre>
<p>This is nice because I can quickly switch sessions within Tmux with <code>Ctrl-b s</code>.</p>
<p>I also have other sessions for Clojure projects and so forth that I&#8217;ve configured for hacking around on the weekend. Go Tmux!</p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/tech/instant-django-dev-environments-with-tmux-tmuxinator-and-virtualenvwrapper/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Self-Reliant Veganism</title>
		<link>http://andrewbrookins.com/books/self-reliant-veganism/</link>
		<comments>http://andrewbrookins.com/books/self-reliant-veganism/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 15:10:04 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[books]]></category>
		<category><![CDATA[food]]></category>
		<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=359</guid>
		<description><![CDATA[&#8220;Trust thyself: every heart vibrates to that iron string.&#8221; When I first read &#8220;Self-Reliance,&#8221; these words sunk into me, but I must have skimmed the rest of the essay. Emerson&#8217;s style and vocabulary put me off, an experience which I attributed to 150 years of drift in the English language. The problem only got worse [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;Trust thyself: every heart vibrates to that iron string.&#8221;</p>
<p>When I first read &#8220;Self-Reliance,&#8221; these words sunk into me, but I must have skimmed the rest of the essay. Emerson&#8217;s style and vocabulary put me off, an experience which I attributed to 150 years of drift in the English language. The problem only got worse as I read his other essays: I kept wondering when he would get to the point, or worse, if he had a point worth getting to (see: &#8220;English Traits&#8221;).</p>
<p>Recently I pulled down from the shelf a used, still-beautiful American Library hardcover collection of Emerson&#8217;s works I&#8217;d been lugging around, and decided to give him a second chance, starting with &#8220;Self-Reliance.&#8221; This time, the essay had a more powerful effect. Themes that were obscure before &#8212; the challenge to find original thought, Emerson&#8217;s pleas for the reader (or perhaps the writer) to avoid conformity &#8212; now seemed to apply to my life in unexpected ways.</p>
<p>If I want to be fully human, I need to create my own ideas &#8212; I can&#8217;t merely adopt ones I find lying around. Coming from Emerson, this otherwise bland message is a sharp reminder that even when I think I&#8217;ve worked something out, I still need to maintain the &#8220;integrity&#8221; of my mind, through the proper care and feeding of my ideas. Take veganism, for example: I can decide, given some evidence and critical thought, to eat a vegan diet, but pretty soon I may start calling myself a vegan, which means opting in to the vegan community. And that is quite a mixed bag, in Emerson&#8217;s view. Claiming membership for oneself in such a group poses a problem: what if I act not because I still believe in the shared values of the group, but because I want to continue to belong, to be known as, a vegan? The question evokes Foucault&#8217;s analysis of the Panopticon, a prison in which the prisoners know they are being watched, but do not know <em>when.</em> A human being living a busy, highly-connected life can find him or herself in this role far too often, I think, and the result is that our actions mean different things than we pretend they do. If we act with the warden on our back, then the meaning and our ultimate experience of our act changes; ideals may become prisons.</p>
<p>All that aside, I can&#8217;t claim to be a perfect vegan. After a year or so of trying to eat a vegan diet, I&#8217;m enthused and especially happy to live closer to an ideal that Peter Singer originally drove home for me. On some occasions I&#8217;ve called myself a vegan and have been called one. But have I been 100% consistent? No. Every once and a while I eat something that I know or suspect has dairy in it. Usually this happens when someone offers me food as a gift, or when I&#8217;m at a restaurant and I forget to ask. At these times I have competing values. Sometimes I value generosity from another human being more than I value my decision not to eat animal products. Likewise with waste: I can&#8217;t ever send food back; I hate wasting food.</p>
<p>I suspect that the desire to remain consistent in action, despite feeling conflicted, is a problem other vegans face. The world is complex, and we respond to it with principles that sometimes compete. Emerson would probably find that acceptable. The integrity of my mind is more important than achieving 100% consistency. After all, if the primary reason I eat tofu instead of cheese on any given day is that I wish to identify as a vegan, and not because I consider tofu healthier for the planet, then I will have lost my integrity, even if I remained consistent in action. As Emerson wrote, &#8220;I ask primary evidence that you are a man, and refuse this appeal from the man to his actions.&#8221; Not only my actions, but also my intentions, create the evidence that I am truly human.</p>
<p>Of course, what occurs to me as examples of &#8220;foolish consistency&#8221; may not occur to you. In my day-to-day life I think most about my family, technology, and food politics. A healthy critique of IT industry wisdom would do me good, but not you, perhaps. Instead, I will only encourage you to read &#8220;Self-Reliance.&#8221; And then, join me in <em>re-reading </em>it, some years from now, after the dust has settled,  so that we can snap to attention once again.</p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/books/self-reliant-veganism/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>No More Supermarket Blues</title>
		<link>http://andrewbrookins.com/life/254/</link>
		<comments>http://andrewbrookins.com/life/254/#comments</comments>
		<pubDate>Sun, 22 Aug 2010 18:16:20 +0000</pubDate>
		<dc:creator>Andrew</dc:creator>
				<category><![CDATA[food]]></category>
		<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://andrewbrookins.com/?p=254</guid>
		<description><![CDATA[A few weeks ago, Kim and I were riding home from our weekly trip to Fred Meyer, and I had an epiphany: I never wanted to go back. Kim wasn’t fond of Fred Meyer, either, so we hatched a plan to limit how much time we spent at the supermarket, and how much we bought, [...]]]></description>
			<content:encoded><![CDATA[<p>A few weeks ago, Kim and I were riding home from our weekly trip to Fred Meyer, and I had an epiphany: I never wanted to go back.</p>
<p>Kim wasn’t fond of Fred Meyer, either, so we hatched a plan to limit how much time we spent at the supermarket, and how much we bought, by buying groceries in bulk once for the entire month. Since we&#8217;d need a car for the monthly trip, we bought a membership at <a href="http://www.zipcar.com/" target="_blank">Zipcar</a>, which has a hybrid available to rent for $7/hour. We had joined a CSA program through <a href="http://www.helsingfarmcsa.com/" target="_blank">Helsing Junction Farms</a>, which we would rely on for our weekly produce; and on the weekends we would buy a couple of items, like Dave’s Killer Bread (PS, this bread has <a href="http://www.daveskillerbread.com/story.shtml" target="_blank">an awesome story</a>), at a local farmer&#8217;s market.</p>
<p>The plan has worked out so well that I’m not sure how we ever put up with the supermarket circus four times every month.</p>
<p>With all the time we’re saving not wandering the dizzying aisles of the supermarket, I’ve had time to reflect on why our experience buying directly from farmers, both at the farmer’s market and through our CSA, has meant so much to me.</p>
<p>I grew up in the suburbs of California and Oregon, shopping with my parents at all the popular big-box megastores. As an adult, I often gravitated back to these stores to avoid the hassle of traveling to multiple places to buy my food and household items. Fred Meyer (AKA Kroger’s), for example, sells produce, bulk food, socks, shoes, computers, toiletries, pharmaceuticals, vacuums, jewelry, bikes, plants, Christmas trees &#8212; the list is effectively endless, and I could always get 90% of what I need there.</p>
<p>During my early 20s, I began to have misgivings about this kind of store. Driving out to visit my parents in Gresham, I thought the concrete and retail blight of outer Portland was an eyesore compared to the Columbia River and the trees along the Washington border. These negative feelings peaked in 2006, after I returned from <a href="http://ghanadrew.blogspot.com/">a trip to Ghana</a>. While there, I had experienced a completely different approach to life than what I&#8217;d grown up with. One of the most notable differences was the central market. In Tamale, Kumasi, and Accra, Ghana’s major cities, I roamed immense central markets that twisted and surged with life. These markets were like cities within cities, and were constantly filled with people who came to buy food and supplies, in many cases directly from the people who ran the farms and from the tailors and craftspeople whose shops lay hidden like bright jewels within the catacomb of the market. These places were all the more beautiful because they appeared to be the creation of the Ghanaians who lived in those cities: over the years, new things &#8212; baubles, plastics and electronics &#8212; had all been grafted onto the timeless root at the center, the market.</p>
<p>Ghana showed me a way of life I never knew in the United States. The memories I had of Ghanaian markets lingered when I came back to Portland and had to interact, once again, with huge megastores owned by corporations that had no real stake in the cities in which they did business. Where were all the people selling food and things they worked to harvest or create? What kind of stuff was I buying, really? Most of it was factory-churned, bland, out-of-season, over-priced stuff harvested and created by, in many cases, low-paid workers, and the profits of the sales flowed directly out of Portland, Oregon. I know that my memory of Ghana was not informed by years of observation &#8212; I had my rose-tinted tourist glasses on &#8212; and the story there can’t really be too different from the story here (I&#8217;m sure not all of those people were selling stuff they had made, or food they&#8217;d harvested!). But, being there, and then returning home, helped me to realize an ideal I had for the way commerce should happen.</p>
<p>I wanted to incorporate parts of the Ghanaian lifestyle into my life, somehow; maybe not everything, but the good stuff, including the way I bought my food and supplies. Doing so proved hard. On my own, it seemed like I couldn’t really make a difference, even with something that appeared to be simple. Then I met Kim, and for a while, all the fun we were having getting to know each other led me to forget some of my ill feelings. Kim and I regularly shopped at Target, buying imported goods; we purchased electronics at Best Buy, furniture at Ikea, and groceries at Fred Meyer. My dissatisfaction with the American retail and food machine had not gone away, though. It only smoldered quietly.</p>
<p>Skip ahead to 2010. Kim and I weren’t exactly planning to drop out of mainstream American culture, but that is what seems to have happened. Over the past couple of years, we moved twice, each time closer to the inner-city. Pretty soon, we’d ditched our car for bicycles; we’d become vegetarians, then vegans, and had started buying mostly organic, local food. I resisted some of these changes, at first &#8212; especially buying organic and going vegan &#8212; while, at the same time, the more Kim read about the food industry, the more unhappy she felt with how we ate. All the cheap, factory-produced food; bland, imported produce; chemical-enhanced, boxed and double-packaged goods! I was like, “I can’t change. I don’t want to change!” But, once Kim got excited about finding an alternative, I started to feel excited, too, and before long we were creating for ourselves the kind of life I’d dreamed about since coming back from Africa. We bought more organic and local food, explored farmer’s markets, and shopped at local-farm-friendly stores like New Seasons.</p>
<p>Now, I know what I want from the experience of buying food and supplies:</p>
<ol>
<li>Cut out the middle man &#8212; buy direct when possible</li>
<li>Support Willamette Valley, Oregon, and Washington farmers</li>
<li>Do business in a community-owned and -operated space (not a corporate market)</li>
<li>A fun atmosphere, a place of joy</li>
</ol>
<p>In Fred Meyer, the bulk of our purchases were in a single produce aisle and a small island of “health food” hidden between a dozen aisles of beer, wine, cookies and cake. We usually locked our bikes at the opposite end of the store from the food, due to the direction we were coming from, which meant that we had to walk through half a mile of cluttered superstore nonsense, listening to elevator music and dodging lots of unhappy-looking people. Now, we have a much more enjoyable time buying organic food grown locally and responsibly, without hurting animals and without factories: once a week, Kim rides her bike to a house in our neighborhood to pick up the CSA box, and every Saturday we visit the farmer’s market at Portland State University where we buy food directly from farmers growing in the Willamette Valley and elsewhere in the Pacific Northwest.</p>
]]></content:encoded>
			<wfw:commentRss>http://andrewbrookins.com/life/254/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

