<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7398379322753724627</id><updated>2012-02-10T11:10:28.085-08:00</updated><category term='specs2'/><category term='element_of'/><category term='invalid resource'/><category term='prompt'/><category term='Windows XP'/><category term='templates'/><category term='Yum'/><category term='Outlook'/><category term='ps1'/><category term='development'/><category term='free'/><category term='junit'/><category term='registers'/><category term='array'/><category term='Backreference'/><category term='chrome'/><category term='Testing'/><category term='applescript'/><category term='poppendieck'/><category term='passenger'/><category term='caltrain'/><category term='amend'/><category term='git'/><category term='Arel'/><category term='nginx'/><category term='rails'/><category term='classes'/><category term='function'/><category term='teardown'/><category term='Mac OS X'/><category term='History'/><category term='cron'/><category term='openSUSE'/><category term='broken'/><category term='parameterized'/><category term='scala'/><category term='escape sequence'/><category term='mysql'/><category term='local'/><category term='CentOS'/><category term='Cake Pattern'/><category term='gerrit'/><category term='macros'/><category term='rc'/><category term='ffmpeg'/><category term='sbt'/><category term='callback'/><category term='format'/><category term='after'/><category term='bash'/><category term='defined types'/><category term='include_path'/><category term='IndexOutOfBoundsException'/><category term='puppet'/><category term='visual studio'/><category term='Bits'/><category term='Includes'/><category term='software'/><category term='color'/><category term='mac'/><category term='parameter'/><category term='missing logs'/><category term='encode'/><category term='error'/><category term='gotcha'/><category term='delegate'/><category term='svn'/><category term='return'/><category term='file_exists'/><category term='javascript'/><category term='Dependency Injection'/><category term='jenkins'/><category term='Selenium'/><category term='ipad'/><category term='Mock'/><category term='concatenate'/><category term='Drop'/><category term='delete'/><category term='specs'/><category term='agile'/><category term='avi'/><category term='script'/><category term='ref-log'/><category term='scalatra'/><category term='scalatraspec'/><category term='drag-and-drop'/><category term='Storage'/><category term='mockito'/><category term='HTML5'/><category term='linux'/><category term='lean'/><category term='CLI'/><category term='subshell'/><category term='convert'/><category term='Bytes'/><category term='Gems'/><category term='tar'/><category term='Groups'/><category term='PHP'/><category term='IntelliJ'/><category term='scrum'/><category term='Ruby'/><category term='scalatratests'/><category term='unix'/><category term='PHPUnit'/><category term='Rails 3'/><category term='log4net'/><category term='exit'/><category term='VIM'/><category term='Stub'/><category term='profile'/><title type='text'>A Sheep Apart</title><subtitle type='html'>Thoughts on concepts across suitable subjects.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>41</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-2966150678517135578</id><published>2012-02-09T11:51:00.000-08:00</published><updated>2012-02-09T11:55:26.484-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mock'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Cake Pattern'/><category scheme='http://www.blogger.com/atom/ns#' term='Dependency Injection'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='PHPUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='Stub'/><title type='text'>Introducting Diesel - PHP Dependency Injection</title><content type='html'>PHPUnit made unit testing PHP an actual pleasant experience, but there's still something missing when it comes to generically injecting stubs and mock behavior into your classes when your classes extend beyond simple relationships.&lt;br /&gt;&lt;br /&gt;Either you end up with constructors that take endless lists of parameters or with shifty setter methods that can leave your classes-under-test in undesirable states of non-initialization. I.e &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;$class = new Klass(); $class-&amp;gt;setSomeReference($mockedObject);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/box/bart/blob/master/lib/Diesel.php" target="_blank"&gt;Diesel&lt;/a&gt; was born out of the need to avoid both of these situations in a reusable and easily understandable manner. Diesel is pure PHP and does not rely on attributes or XML files. It's not quite a &lt;a href="http://www.warski.org/blog/2011/04/di-in-scala-cake-pattern-pros-cons/" target="_blank"&gt;cake pattern&lt;/a&gt; -- PHP does not provide mix-in capabilities -- but does provide a similar concept of defining a default implementation for your production environment use cases and respectively (optionally) granularly stubbing out all of your test use cases.&lt;br /&gt;&lt;br /&gt;The Diesel system itself is one small PHP class. It works by relying on some static cooperation from each dependent class to implement a method which will register all of its production dependencies. For non-production use cases (i.e. Testing), it relies on each test to configure a non-static Diesel instance with each dependency for the given class under test -- most commonly each dependency will be stubbed using PHPUnit::getMock().&lt;br /&gt;&lt;br /&gt;Dependencies for a class may be registered statically or locally, where a local registration is local to the instance upon which it was registered (i.e. no other Diesels will be affected by it). Both registration methods have the same signature,&amp;nbsp;&lt;span class="nf" style="background-color: white; color: #990000; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;register&lt;/span&gt;&lt;span class="p" style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;(&lt;/span&gt;&lt;span class="nv" style="background-color: white; color: teal; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;$owner&lt;/span&gt;&lt;span class="p" style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;,&lt;/span&gt;&lt;span style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; white-space: pre;"&gt; &lt;/span&gt;&lt;span class="nv" style="background-color: white; color: teal; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;$class&lt;/span&gt;&lt;span class="p" style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;,&lt;/span&gt;&lt;span style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; white-space: pre;"&gt; &lt;/span&gt;&lt;span class="nv" style="background-color: white; color: teal; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;$instantiate&lt;/span&gt;&lt;span class="p" style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;)&lt;/span&gt;. &amp;nbsp;Consumers of Diesel can produce their dependent objects by using its non-static factory method which roughly resembles,&amp;nbsp;&lt;span style="background-color: white; color: #990000; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; font-weight: bold; line-height: 16px; white-space: pre;"&gt;create&lt;/span&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;(&lt;/span&gt;&lt;span class="nv" style="background-color: white; color: teal; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;$owner&lt;/span&gt;&lt;span class="p" style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;,&lt;/span&gt;&lt;span style="background-color: white; color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; white-space: pre;"&gt; &lt;/span&gt;&lt;span class="nv" style="background-color: white; color: teal; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;"&gt;$class&lt;/span&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;)&lt;/span&gt;-- further specified later.&lt;br /&gt;&lt;br /&gt;Ok, so what does all of this mean? Let's move into a real world example. One of the utilities built into our build and release tools (&lt;a href="https://github.com/box/bart/" target="_blank"&gt;Bart&lt;/a&gt;) project is a "stop the line" git pre-receive hook. The hook simply queries our development Jenkins server for the status of the latest build. If that build passed, then the commit is permitted, otherwise &lt;i&gt;only &lt;/i&gt;commits whose message contains "{buildfix}" may proceed. This is explained in more detail on the project's github home page. &amp;nbsp;The core class behind this feature relies on two other classes: a Jenkins class and a Git class.&lt;br /&gt;&lt;br /&gt;In order to test our Stop-the-Line class, we need to stub out method calls to the Jenkins and Git classes. This is a perfect situation for Diesel to inject stub classes. &amp;nbsp;So let's see how it works below. For the eager, you may find the entire test class at &lt;a href="https://github.com/box/bart/blob/master/test/lib/Git_Hook/Stop_The_Line_Test.php" target="_blank"&gt;Stop The Line Test.php&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;First, we must configure Stop_The_Line to work with Diesel. That means defining the registration method and accepting a Diesel instance to its constructor. &lt;i&gt;Wait&lt;/i&gt;! Didn't I say earlier that taking injection classes as constructor parameters was bad? Well, I've concluded that it's only bad to the extent that they produce unmanageable lists of params. In Diesel's case, &lt;i&gt;all &lt;/i&gt;of your injection is controlled by &lt;i&gt;only one &lt;/i&gt;parameter. Not a bad compromise. So, Ok, back to the code.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:php"&gt;class Stop_The_Line {&lt;br /&gt;  // The constructor param at the end&lt;br /&gt;  public function __construct($git_dir, $conf, Diesel $di = null) {&lt;br /&gt;    // Use the default static dependencies?&lt;br /&gt;    $this-&amp;gt;di = $di ?: new Diesel();&lt;br /&gt;&lt;br /&gt;    // Use Diesel to produce an instance of a Jenkins Job&lt;br /&gt;    // Notice how Jenkins params are passed in optional 3rd param here&lt;br /&gt;    $this-&amp;gt;job = $di-&amp;gt;create($this, 'Jenkins_Job', array(&lt;br /&gt;      'host' =&amp;gt; $conf['host'],&lt;br /&gt;      'job_name' =&amp;gt; $conf['job_name'],&lt;br /&gt;      'w' =&amp;gt; $w,&lt;br /&gt;    ));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // This method will be automatically called by Diesel IF and ONLY IF&lt;br /&gt;  // ...there is no local or static registration for Stop_The_Line&lt;br /&gt;  public static function dieselify($me)&lt;br /&gt;  {&lt;br /&gt;    Diesel::register_global($me, 'Git', function($params) {&lt;br /&gt;      return new Git($params['git_dir']);&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;    Diesel::register_global($me, 'Jenkins_Job', function($params) {&lt;br /&gt;      return new Jenkins_Job($params['host'], $params['job_name'], $params['w']);&lt;br /&gt;    });&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, our production code can use Stop_The_Line with its default dependencies simply by omitting the last parameter to the constructor. &amp;nbsp;Test code can inject instances of Jenkins_Job and Git by passing in a so contrived Diesel instance as the last parameter to the constructor.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:php"&gt;&lt;br /&gt;class Stop_The_Line_Test extends Bart_Base_Test_Case {&lt;br /&gt;  public function testStopTheLine() {&lt;br /&gt;    $job_name = 'the build';&lt;br /&gt;    $conf = array('host' =&amp;gt; '...', 'job_name' =&amp;gt; $job_name);&lt;br /&gt;&lt;br /&gt;    // This is the Diesel ONLY for this test i.e. NO other tests&lt;br /&gt;    // ...will be affected by the dependencies it defines&lt;br /&gt;    $di = new Diesel();&lt;br /&gt;&lt;br /&gt;    $this-&amp;gt;configureJenkinsJob($di, $job_name, $conf);&lt;br /&gt;    $this-&amp;gt;configureGit($di);&lt;br /&gt;&lt;br /&gt;    // Our contrived Diesel will be used when STL produces the Jenkins Job&lt;br /&gt;    // ...and it's Git instance&lt;br /&gt;    $stl = new Stop_The_Line('.git', $conf, $di);&lt;br /&gt;&lt;br /&gt;    // We expect the line to stop because BOTH checks fail:&lt;br /&gt;    // 1. Jenkins build failed,&lt;br /&gt;    // 2. Commit message did not contain {buildfix}&lt;br /&gt;    $this-&amp;gt;assert_throws('Exception', 'Jenkins not healthy', function() use($stl) {&lt;br /&gt;      $stl-&amp;gt;verify('hash');&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;  }  &lt;br /&gt;&lt;br /&gt;  private function configureJenkinsJob(Diesel $di, $job_name, $conf) {&lt;br /&gt;    // Use PHPUnit to create a stub job&lt;br /&gt;    $mock_job = $this-&amp;gt;getMock('Jenkins_Job', array(), array(), '', false);&lt;br /&gt;  &lt;br /&gt;    // And set it up to say the last build failed&lt;br /&gt;    $mock_job-&amp;gt;expects($this-&amp;gt;once())&lt;br /&gt;      -&amp;gt;method('is_healthy')&lt;br /&gt;      -&amp;gt;will($this-&amp;gt;returnValue(false));&lt;br /&gt;&lt;br /&gt;    // Now register this stub job for ONLY this Diesel instance&lt;br /&gt;    $phpu = $this;&lt;br /&gt;    $di-&amp;gt;register_local('Git_Hook_Stop_The_Line', 'Jenkins_Job',&lt;br /&gt;      function($params) use($phpu, $conf, $job_name, $mock_job) {&lt;br /&gt;        $phpu-&amp;gt;assertEquals($job_name, $params['job_name'],&lt;br /&gt;            'Jenkins job name did not match');&lt;br /&gt;&lt;br /&gt;        $phpu-&amp;gt;assertEquals($conf['host'], $params['host'],&lt;br /&gt;            'Expected host to match conf');&lt;br /&gt;&lt;br /&gt;        return $mock_job;&lt;br /&gt;    });&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private function configureGit(Diesel $di) {&lt;br /&gt;    $mock_git = $this-&amp;gt;getMock('Git', array(), array(), '', false);&lt;br /&gt;&lt;br /&gt;    // Stop the Line checks if commit message contains {buildfix}&lt;br /&gt;    // Let's see what happens when it doesn't&lt;br /&gt;    $mock_git-&amp;gt;expects($this-&amp;gt;once())&lt;br /&gt;      -&amp;gt;method('get_commit_msg')&lt;br /&gt;      -&amp;gt;with($this-&amp;gt;equalTo('hash'))&lt;br /&gt;      -&amp;gt;will($this-&amp;gt;returnValue('The commit message'));&lt;br /&gt;&lt;br /&gt;     $di-&amp;gt;register_local('Git_Hook_Stop_The_Line', 'Git',&lt;br /&gt;      function($params) use($mock_git) {&lt;br /&gt;       return $mock_git;&lt;br /&gt;     });&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So as you can see, Diesel lets you granularly control the injection of multiple dependencies per system under test &lt;i&gt;per &lt;/i&gt;test. Moreover, it does this in a pure PHP fashion giving programmatic power that just isn't offered (easily or transparently) by XML. In contrast to a annotation based system that injects dependencies via object reflection, Diesel allows you naturally call object constructors and allows those constructors to completely configure themselves in a straightforward manner. A reflection based system requires you to have empty constructors and hides actual implementations from the developer, which can lead to misunderstandings and bugs.&lt;br /&gt;&lt;br /&gt;More details can actually be found at the link to the test I provided above. My code above was extracted thence and then tweaked to make it a little simpler (i.e. maybe I made some mistakes). Also, you can see examples how Diesel can be used within a chain of inheritance and for multiple injected classes. In fact, I encourage you to do so as that is where the full utility of Diesel really shines.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-2966150678517135578?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/2966150678517135578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2012/02/introduction-diesel-php-dependency.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2966150678517135578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2966150678517135578'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2012/02/introduction-diesel-php-dependency.html' title='Introducting Diesel - PHP Dependency Injection'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-1512105036832223142</id><published>2012-02-02T09:56:00.000-08:00</published><updated>2012-02-02T19:38:18.678-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='format'/><category scheme='http://www.blogger.com/atom/ns#' term='ffmpeg'/><category scheme='http://www.blogger.com/atom/ns#' term='free'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='avi'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><category scheme='http://www.blogger.com/atom/ns#' term='encode'/><category scheme='http://www.blogger.com/atom/ns#' term='convert'/><title type='text'>Encode AVI for iPad (for Free)</title><content type='html'>I wanted to convert an old movie of mine to m4v so that I could watch it on my iPad. I was unable to import it into my iTunes since the format didn't match, so I had to convert it to a format that makes iTunes happy -- namely mpeg4.&lt;br /&gt;&lt;br /&gt;Since I didn't want to pay for Handbrake (and they don't have a default iPad format), I decided to just do it myself using ffmpeg.&lt;br /&gt;&lt;br /&gt;I am on a mac, so I needed to install ffmpeg. The easiest way to do that was to use &lt;a href="https://github.com/mxcl/homebrew/wiki/Installation" target="_blank"&gt;homebrew&lt;/a&gt;. My first attempt to install failed because home brew had some issues. &amp;nbsp;As it ended up, I had to uninstall home brew &lt;i&gt;and&lt;/i&gt; uninstall mac ports (don't forget &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;sudo rm /usr/local/bin/{brew,port}&lt;/span&gt;)! I went through some drama with my Ruby installation (1.8.7), since home brew wasn't loading, which involved using rvm to install 1.9.3, then 1.9.2, and then back to my system install, which suddenly started working again with the brew install script.&lt;br /&gt;&lt;br /&gt;Next:&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; brew install ffmpeg&lt;/span&gt;. This got me *&lt;b&gt;all&lt;/b&gt;* the required dependencies for ffmpeg in one go! Awesome.&lt;br /&gt;&lt;br /&gt;Next, the encoding line:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ffmpeg -i myMovieFile.avi -acodec libfaac -ac 2 -ab 160k -s 1024x768 -vcodec libx264 -vpre iPod640 -b 1200k -f mp4 -threads 0 myMovieFile.ipad.aac&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;which I adapted from,&amp;nbsp;&lt;a href="https://develop.participatoryculture.org/index.php/ConversionMatrix"&gt;https://develop.participatoryculture.org/index.php/ConversionMatrix&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-1512105036832223142?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/1512105036832223142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2012/02/encode-avi-for-ipad.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/1512105036832223142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/1512105036832223142'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2012/02/encode-avi-for-ipad.html' title='Encode AVI for iPad (for Free)'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-8937846754077619780</id><published>2012-02-01T18:09:00.000-08:00</published><updated>2012-02-06T15:11:45.952-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='after'/><category scheme='http://www.blogger.com/atom/ns#' term='specs2'/><category scheme='http://www.blogger.com/atom/ns#' term='scalatraspec'/><category scheme='http://www.blogger.com/atom/ns#' term='teardown'/><category scheme='http://www.blogger.com/atom/ns#' term='scalatratests'/><category scheme='http://www.blogger.com/atom/ns#' term='scalatra'/><title type='text'>Testing Scalatra with Immutable Specs2</title><content type='html'>&lt;pre class="brush:java"&gt;import org.specs2.Specification&lt;br /&gt;import org.specs2.mock.Mockito&lt;br /&gt;import org.scalatra.test.ScalatraTests&lt;br /&gt;import org.eclipse.jetty.testing.ServletTester&lt;br /&gt;import org.specs2.specification.After&lt;br /&gt;&lt;br /&gt;class MySpec extends Specification { def is = &lt;br /&gt;  "My spec must" ^&lt;br /&gt;  "verify that scalatra can be tested" ! Specs().assert()&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Create a new jetty context each time&lt;br /&gt;   * This lets us mock expectations *per* specification&lt;br /&gt;   */&lt;br /&gt;  case class Specs() extends After with ScalatraTests with Mockito {&lt;br /&gt;    // The servlet tester gives an http context to your tests&lt;br /&gt;    lazy val tester = new ServletTester&lt;br /&gt;    tester.start()&lt;br /&gt;&lt;br /&gt;    val myMock = mock[MyObject]&lt;br /&gt;&lt;br /&gt;    // Register your servlet with the context and inject the mock&lt;br /&gt;    addServlet(new MyServlet(myMock), "/*")&lt;br /&gt;&lt;br /&gt;    // don't leave the jetty context hanging around&lt;br /&gt;    def after { tester.stop() }&lt;br /&gt;&lt;br /&gt;    // Pay special attention to the "this" keyword, which will provide the&lt;br /&gt;    // ...method in a scope such that "after" may be called for teardown&lt;br /&gt;    def assert() = this {&lt;br /&gt;      // Just some expectation on the mock object&lt;br /&gt;      myMock.get(0) returns true&lt;br /&gt;&lt;br /&gt;      get("/") {&lt;br /&gt;        there was one(myMock).get(0)&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-8937846754077619780?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/8937846754077619780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2012/02/testing-scalatra-with-immutable-specs2.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/8937846754077619780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/8937846754077619780'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2012/02/testing-scalatra-with-immutable-specs2.html' title='Testing Scalatra with Immutable Specs2'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-7109702312021028231</id><published>2012-01-29T20:00:00.000-08:00</published><updated>2012-01-29T20:00:27.621-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='invalid resource'/><category scheme='http://www.blogger.com/atom/ns#' term='puppet'/><category scheme='http://www.blogger.com/atom/ns#' term='classes'/><category scheme='http://www.blogger.com/atom/ns#' term='parameterized'/><category scheme='http://www.blogger.com/atom/ns#' term='defined types'/><title type='text'>Puppet: Multiple Classes &amp; Inheritance</title><content type='html'>I learned about a very cool thing yesterday: &lt;a href="http://docs.puppetlabs.com/learning/definedtypes.html"&gt;Defined Types in Puppet.&lt;/a&gt; Previously, I was trying to use parameterized classes for code reusability, but the problem there is that you can only declare one class resource per node. So puppet would yell if you tried to use the same parameterized class more than once on the same node. That's where defined types come in, they let you essentially declare a constructor like you would for a class, but as a method signature. Then, you can declare as many as you want and give them names. &lt;br /&gt;&lt;br /&gt;The tie in to how to use this with classes and inheritance is to run the Defined Type declaration within each of your individual classes. &lt;br /&gt;&lt;br /&gt;Defined types are not auto-loaded in the same fashion as the rest of the modules, so it's necessary to define them in a file named "init.pp" Otherwise they won't load and you'll see lots of errors like, "&lt;i&gt;err: Could not retrieve catalog from remote server: Error 400 on SERVER: Puppet::Parser::AST::Resource failed with error ArgumentError: Invalid resource my_defined_resource at .../modules/module_name/manifests/my_manifest.pp:8 on node node.f.q.d.n&lt;/i&gt;"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-7109702312021028231?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/7109702312021028231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2012/01/puppet-multiple-classes-inheritance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7109702312021028231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7109702312021028231'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2012/01/puppet-multiple-classes-inheritance.html' title='Puppet: Multiple Classes &amp; Inheritance'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-5133404821005142442</id><published>2012-01-13T15:57:00.000-08:00</published><updated>2012-01-13T15:57:05.254-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='callback'/><category scheme='http://www.blogger.com/atom/ns#' term='specs'/><category scheme='http://www.blogger.com/atom/ns#' term='parameter'/><category scheme='http://www.blogger.com/atom/ns#' term='mockito'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><category scheme='http://www.blogger.com/atom/ns#' term='delegate'/><title type='text'>Specs2 Mockito - Invoke Injected Callback</title><content type='html'>Mockito and Specs2 work great together and make testing my code a lot of fun. I ran into a problem yesterday in which I needed to get access to a callback function that was passed into an object that I was mocking. For some concreteness, I was mocking a zookeeper client and needed to invoke the callback function I passed to "zookeeper.watchNode(path, callbackFunction)".&lt;br /&gt;&lt;br /&gt;Up until this point, I've only needed to verify arguments from my test. I haven't needed to actually do something with the argument itself. My original approach was to use a custom matcher to capture the parameter using &lt;a href="https://groups.google.com/forum/#!msg/specs2-users/R3DS_ZPe29w/WvmkfJqcq8IJ" target="_blank"&gt;function matchers&lt;/a&gt;. But that involved a var and was rather messy.&lt;br /&gt;&lt;br /&gt;It turns out there is a MUCH better way to do this. Called "&lt;a href="http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#15" target="_blank"&gt;argument capture&lt;/a&gt;." In my case, my code looked like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java"&gt;&lt;br /&gt;      // The signature of the zookeeper watch function&lt;br /&gt;      val listener = capture[(Option[Array[Byte]]) =&gt; Unit]&lt;br /&gt;&lt;br /&gt;      // create system under test, which will call watchNode internally&lt;br /&gt;      new SUT(zkMock)&lt;br /&gt;&lt;br /&gt;      // Use the arg capturers to capture the params SUT passed in&lt;br /&gt;      there was one(zkMock).watchNode(path, listener)&lt;br /&gt;&lt;br /&gt;      // Now, call the callback method&lt;br /&gt;      listener.value(Some("some updated value from zookeeper"))&lt;br /&gt;&lt;br /&gt;      SUT.someValue must_== "some updated value"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-5133404821005142442?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/5133404821005142442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2012/01/specs2-mockito-invoke-injected-callback.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5133404821005142442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5133404821005142442'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2012/01/specs2-mockito-invoke-injected-callback.html' title='Specs2 Mockito - Invoke Injected Callback'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-1124974860505751804</id><published>2012-01-12T12:28:00.001-08:00</published><updated>2012-01-12T12:28:24.626-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='specs2'/><category scheme='http://www.blogger.com/atom/ns#' term='IndexOutOfBoundsException'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Specs2: IndexOutOfBoundsException: 30</title><content type='html'>I was consistently seeing a java.lang.IndexOutOfBoundsException: 30 exception today while working on some code. I had written a spec with a single use case, which was marked as pending because I couldn't test my trait until I flushed out another piece of code upon which it depended.&lt;br /&gt;&lt;br /&gt;I'd seen the error in the past, but couldn't remember how (of it) it went away. Since I was working on a pretty much skeleton spec, I figured now would be a good time to get to the bottom of it.&lt;br /&gt;&lt;br /&gt;Well, it was pretty simple! In connecting my use case text description to the actual test, I was using a "^" instead of an "!", which also explains the other oddity I was seeing (that I had thought related to pending tests) "No source file found at src/test/scala/...", since the "^" was expecting a String as the result of my test method being run, not a Specs result. Go DSLs!&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java"&gt;&lt;br /&gt;def is =&lt;br /&gt;"My trait should" ^&lt;br /&gt;"do what I want" ^ SpecsStub().assert() // WRONG, ^ should be !&lt;br /&gt;&lt;br /&gt;case class SpecsStub() {&lt;br /&gt;  def assert() = {&lt;br /&gt;    pending&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-1124974860505751804?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/1124974860505751804/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2012/01/specs2-indexoutofboundsexception-30.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/1124974860505751804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/1124974860505751804'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2012/01/specs2-indexoutofboundsexception-30.html' title='Specs2: IndexOutOfBoundsException: 30'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-802115956779026151</id><published>2011-12-02T15:29:00.001-08:00</published><updated>2011-12-02T17:24:17.211-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='include_path'/><category scheme='http://www.blogger.com/atom/ns#' term='file_exists'/><category scheme='http://www.blogger.com/atom/ns#' term='PHPUnit'/><title type='text'>Does File Exist in PHP Include Path?</title><content type='html'>&lt;br /&gt;We built a wrapper script around PHPUnit that loads and configures our application for testing so that test authors need not pepper their test files with redundant lines like "&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;require_once dirname(...) . '/setup/file/included/in/all/tests.php&lt;/span&gt;'". This in itself is actually pretty cool, but that's fodder for another post =) The wrapper is a big time saver, but it comes at the price of a little consumption of internal PHPUnit implementation, most importantly how it starts itself up.&lt;br /&gt;&lt;br /&gt;The start up invocation changed between 3.5 and 3.6 and one of those changes involved how PHPUnit autoloads classes. This introduced a problem because we needed to be able to support both versions of PHPUnit while the upgrade was underway. Fortunately it turned out that a determining factor between 3.5 and 3.6 was the presence of the "&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Autoload.php&lt;/span&gt;" file in the root of the PHPUnit extension module. Unfortunately, it turned out to be nontrivial to check for the existence of the file using the standard file_exists() method. The problem is that &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;file_exists&lt;/span&gt;() doesn't check PHP's include path for relative file paths (unlike the logic of &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;require_once&lt;/span&gt;()).&lt;br /&gt;&lt;br /&gt;After a little research, we were able to solve the issue by a little bit of fun with &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;file_get_contents&lt;/span&gt;, which takes an additional parameter to let it know that you'd like to check the include path for the presence of the file. Additionally, in the interest of performance, it lets you load only the first byte of the file, rather the entire thing.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:php"&gt;// Support for newer version of PHPUnit during rollout to all VMs                                                                                         &lt;br /&gt;// This will load the first byte of the file from the include path                                                                                         &lt;br /&gt;// ...if it exists                                                                                                                                        &lt;br /&gt;if (@file_get_contents('PHPUnit/Autoload.php', true, null, 0, 1))                                                                                          &lt;br /&gt;{                                                                                                                                                          &lt;br /&gt;    // File exists, we're on 3.6...&lt;br /&gt;    require 'PHPUnit/Autoload.php';                                                                                                                        &lt;br /&gt;    // ... other stuff&lt;br /&gt;} &lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;    // Do stuff for 3.5&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Check out the docs on &lt;a href="http://php.net/manual/en/function.file-get-contents.php" target="_blank"&gt;file_get_contents&lt;/a&gt; for a description of the params.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-802115956779026151?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/802115956779026151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/12/does-file-exist-in-php-include-path.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/802115956779026151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/802115956779026151'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/12/does-file-exist-in-php-include-path.html' title='Does File Exist in PHP Include Path?'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-5084593273110371096</id><published>2011-11-17T10:53:00.001-08:00</published><updated>2011-11-17T12:21:29.302-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='poppendieck'/><category scheme='http://www.blogger.com/atom/ns#' term='lean'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><title type='text'>Notes From Implementing Lean Software Development - From Concept to Cash</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;I read the Poppendieck's book on implementing lean software development almost a year ago and I continue to go back to it for advice and insight. I finally brought myself to put together a brief summary on the first half of the book and decided to share it with my blog readers. One of the great things about the book is the set of industry examples they provide to exemplify to the points that they are making. This is especially useful to me, since I often have no debating ammunition aside from my personal beliefs. To make it easy to look up those examples, I'm including the page numbers along with the ideas below.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;The book can be purchased from&amp;nbsp;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0321620704/poppendieckco-20" target="_blank"&gt;Amazon&lt;/a&gt;.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 24 Early specification does NOT reduce waste, it encourages it&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 28 "Do It Right the First Time"&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;This means TEST first to keep bugs OUT. It does NOT mean think&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;of all possible future needs of the feature.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 32 Forecast predictions, not fact. Avoid "analysis paralysis."&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;Build processes that allow quick feedback and responses, rather&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;than building for an uncertain feature&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 33 "Plans are useless, but planning is indispensable" - Eisenhower&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 34 Achieving high value, low stress feature delivery is impossible&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;WITHOUT superb quality (in the form of tests)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 38 Sub-optimizing is BAD&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;E.g. Optimizing the writing of ONLY the feature code, but NOT&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;the test code&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;--result--&amp;gt; More complex code, higher potential for&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;introducing new bugs, longer to write new code&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;E.g. Optimizing ONLY your part of the process. The overall&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;process still drags along and you get frustrated.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;--solution--&amp;gt; Team ownership!&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 74 7 Wastes&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;Relearning by failing to engage current knowledge&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;--solution?--&amp;gt; Information needs to be accessible. People should&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;not be siloed and should talk often.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 101 Increase estimation reliability by decreasing variability (i.e.&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;estimate and commit to smaller projects)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 105 FASTER delivery --&amp;gt; Reduce the number of things in WIP (queue theory)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 124 Exec thinking is so ingrained that Lean concepts are invisible&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 126 Group is NOT a team until everyone is COMMITTED&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;E.g. Sports - track versus rowing&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 150 Story by Rally does a great job highlighting the DRAWBACKS of&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;Technical DEBT incurred by NOT slowing down to address untested code&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 151 You must *commit* to action items coming out of Retrospectives&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;Nothing is accomplished if you only discuss problems.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;pg 153 More important than processes is LEARNING (understanding),&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;SHARING, and SOLVING PROBLEMS&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;Experience over documentation.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;Refined documentation far&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: rgba(255, 255, 255, 0.917969); color: #222222; font-family: Georgia, 'Times New Roman', serif;"&gt;outweighs garrulous documentation&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-5084593273110371096?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/5084593273110371096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/11/notes-from-implementing-lean-software.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5084593273110371096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5084593273110371096'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/11/notes-from-implementing-lean-software.html' title='Notes From Implementing Lean Software Development - From Concept to Cash'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-4227357753103191975</id><published>2011-11-13T10:59:00.001-08:00</published><updated>2011-11-13T11:09:18.739-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='drag-and-drop'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML5'/><category scheme='http://www.blogger.com/atom/ns#' term='chrome'/><title type='text'>HTML5 Drag and Drop - Chrome Not Working?</title><content type='html'>The W3C standard defines seven event types for drag and drop,&amp;nbsp;&lt;a href="http://dev.w3.org/html5/spec/dnd.html#dndevents"&gt;http://dev.w3.org/html5/spec/dnd.html#dndevents&lt;/a&gt;. &amp;nbsp;Pretty cool to have so many options, but the nieve reader may be surprised to learn how they work together. Specifically, for people binding to the "drop" event.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The default behavior of the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;dragover&lt;/span&gt; event is described as such, &lt;i&gt;"Reset the current drag operation to 'none'"&lt;/i&gt;. So what does this mean for developers binding to the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;drop&lt;/span&gt; event? It means, &lt;b&gt;that unless you prevent the default behavior of &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;dragover&lt;/span&gt;, your &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;drop&lt;/span&gt; event will not fire. &lt;/b&gt;This is not a fun one to learn on your own.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-4227357753103191975?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/4227357753103191975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/11/html5-drag-and-drop-chrome-not-working.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4227357753103191975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4227357753103191975'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/11/html5-drag-and-drop-chrome-not-working.html' title='HTML5 Drag and Drop - Chrome Not Working?'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-7939940927700607261</id><published>2011-11-11T12:39:00.001-08:00</published><updated>2011-11-11T12:42:52.856-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='puppet'/><title type='text'>Could not evaluate: Could not retrieve information from source(s)</title><content type='html'>Oops! I was evaluating a template, NOT a file.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;file {&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; "/destination/file/path":&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; source =&amp;gt; template("path/to/template");&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The key is that "&lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;source&lt;/span&gt;" should be "&lt;span class="Apple-style-span" style="background-color: lime;"&gt;content&lt;/span&gt;"!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;file {&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; "/destination/file/path":&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; content =&amp;gt; template("path/to/template");&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, what was happening behind the scenes is that puppet was trying to source the literal value of the evaluated template file. Could be useful?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-7939940927700607261?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/7939940927700607261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/11/could-not-evaluate-could-not-retrieve.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7939940927700607261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7939940927700607261'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/11/could-not-evaluate-could-not-retrieve.html' title='Could not evaluate: Could not retrieve information from source(s)'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-5717257129252327839</id><published>2011-11-09T21:09:00.000-08:00</published><updated>2011-11-17T15:43:02.413-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='rc'/><title type='text'>Reading /etc/rc.status</title><content type='html'>What Cool Bash Stuff Did I Learn?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;What does RC Stand For?&lt;/b&gt; ==&amp;gt;&amp;nbsp;Resource Control&lt;/li&gt;&lt;li&gt;&lt;b&gt;How do I tell vim my file type is Bash?&lt;/b&gt;&amp;nbsp;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;I can set the following anywhere in the file,&lt;/li&gt;&lt;ul&gt;&lt;li&gt;# vim: set filetype=sh&lt;/li&gt;&lt;li&gt;# vim: syntax=sh&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;&lt;b&gt;How can I make my if()s look prettier?&lt;/b&gt; ==&amp;gt; Use {}&lt;pre class="brush:bash"&gt;[ -e $pathToFile ] || {&lt;br /&gt;   echo &amp;gt;&amp;amp;2 "File $file does not exit"&lt;br /&gt;   exit 1&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;How do I prompt a command to ask me for input?&lt;/b&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;==&amp;gt; cat file-to-prepend - file-to-append &amp;gt; output-file&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-5717257129252327839?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/5717257129252327839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/11/reading-etcrcstatus.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5717257129252327839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5717257129252327839'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/11/reading-etcrcstatus.html' title='Reading /etc/rc.status'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-5123019980306792748</id><published>2011-10-31T15:39:00.000-07:00</published><updated>2011-10-31T15:39:28.189-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='specs2'/><category scheme='http://www.blogger.com/atom/ns#' term='jenkins'/><category scheme='http://www.blogger.com/atom/ns#' term='sbt'/><category scheme='http://www.blogger.com/atom/ns#' term='junit'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Hello Specs2 JUnit, Farewell Henkelmann TestListener</title><content type='html'>Out of the box, SBT 10.1 doesn't give you test results in JUnit output. This is a problem for anyone using Jenkins to process test results. Fortunately, last November, Christoph Henkelmann released a plugin to SBT that plugs in to the test execution life cycle of SBT,&amp;nbsp;&lt;a href="http://henkelmann.eu/junit_xml_listener"&gt;http://henkelmann.eu/junit_xml_listener&lt;/a&gt;. &amp;nbsp;This was great, but had a few bugs with inconsistent results and JUnit data ending up in the wrong file or XML being badly formatted. These bugs occurred inconsistently and infrequently enough to be only a minor annoyance.&lt;br /&gt;&lt;br /&gt;Over this past summer, specs2 added a JUnit output option for its test results. At the time, the documentation didn't fully explain the necessary integration points. So I'll explain what I did to get it working. Most of this information is now available at,&amp;nbsp;&lt;a href="http://etorreborre.github.com/specs2/guide/org.specs2.guide.Runners.html"&gt;http://etorreborre.github.com/specs2/guide/org.specs2.guide.Runners.html&lt;/a&gt; if you search for "junit".&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;// Put this in your SBT build file to output to both console&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;// ...and junit files&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;console is helpful so that you can see the&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;// ...output in jenkins build history&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;testOptions in Test += Tests.Argument("junitxml", "console")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you're running on the command line, you can provide SBT system arguments straight up, like&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;bash $&amp;gt; sbt junitxml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Finally, on the SBT command line, it won't work with the SBT "test" command, but it will work with the SBT "test-only" command.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;sbt-command-line&amp;gt;test-only com.company.class.specs -- junitxml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The other cool learning that I experienced at this time, was with using SBT collections. We have several scala projects and we need to share common SBT properties between them. To accomplish this, we made our own SBT plugin and import all of its settings at the top of each project. One of the settings is the testListener SBT setting, which attaches the junitXmlListener to all our unit test output. Since,&amp;nbsp;I wanted to test out the junitxml flag in only one project before fully committing to it, I couldn't outright remove the test listener for all the projects. So in order to remove only in one project, I used the SBT filter syntax: ~=&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;testListeners ~= { (listeners: Seq[TestReportListener]) =&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp; listeners filterNot ( _.isInstanceOf[JUnitXmlTestsListener] )&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-5123019980306792748?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/5123019980306792748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/10/hello-specs2-junit-farewell-henkelmann.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5123019980306792748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5123019980306792748'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/10/hello-specs2-junit-farewell-henkelmann.html' title='Hello Specs2 JUnit, Farewell Henkelmann TestListener'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-2746069048607008306</id><published>2011-10-26T19:19:00.002-07:00</published><updated>2011-10-26T19:19:40.419-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='gerrit'/><title type='text'>Gerrit Code Review - Unpack error Missing unknown</title><content type='html'>We use the Gerrit code review tool at my company; currently version 2.1.8. Gerrit gives us a lot of tools and is an extremely useful tool for code quality and knowledge sharing (i.e. code reviewing). However, Gerrit can often require some TLC. Today was one of those days.&lt;br /&gt;&lt;br /&gt;While I was doing some maintenance on our git host today, I noticed that git suggested I prune one of our repos. So, I went ahead and pruned. About half an hour later, one of our developers reported that he couldn't create a new patch set in Gerrit -- neither update or create were working. Pretty soon, I was getting several reports of this from the team. They were all getting the same error:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;error: unpack failed: error Missing unknown 3061766be9c324fa47fb4832399b34db5a186276&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;fatal: Unpack error, check server log&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;To ssh://git.dev:29418/webapp&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;! [remote rejected] HEAD -&amp;gt; refs/for/master/master (n/a (unpacker error))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The key part of this message is the git object that's missing,&amp;nbsp;3061766. The git prune must have identified that the object was dangling, no longer necessary, and removed it. However, for some reason, JGit inside of Gerrit still felt the object served some purpose important enough to throw an exception. I tried to find the object in the remote repo and locally, but to no avail, it was history.&lt;br /&gt;&lt;br /&gt;After trying pretty much everything I could find on the internet (&lt;a href="http://code.google.com/p/gerrit/issues/detail?id=585"&gt;http://code.google.com/p/gerrit/issues/detail?id=585&lt;/a&gt;,&amp;nbsp;&lt;a href="http://groups.google.com/group/repo-discuss/browse_thread/thread/cf7095d3dc364c7e/f2c11756a5a0396f?"&gt;http://groups.google.com/group/repo-discuss/browse_thread/thread/cf7095d3dc364c7e/f2c11756a5a0396f?&lt;/a&gt;) and replacing the jgit jar in my tmp .gerritcodereview directory, I finally found a solution.&lt;br /&gt;&lt;br /&gt;The solution was to restore a backup of our git repository to a temp directory and use git cat-file to first verify the object&amp;nbsp;3061766 was valid. Then, I used git verify-pack to find the pack file that contained the commit. Then I copied the pack and its index file (&lt;a href="http://progit.org/book/ch9-4.html"&gt;http://progit.org/book/ch9-4.html&lt;/a&gt;) into our real repo. Shazzam! Gerrit started accepting change sets again!&lt;br /&gt;&lt;br /&gt;In more detail:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;tar -xf backup.tar ./path-to-git-dir&lt;/li&gt;&lt;li&gt;cd path-to-git-dir&lt;/li&gt;&lt;li&gt;git cat-file -t&amp;nbsp;3061766be9c324fa47fb4832399b34db5a186276&lt;/li&gt;&lt;li&gt;cd objects/pack&lt;/li&gt;&lt;li&gt;ls | xargs git verify-pack -v | grep&amp;nbsp;3061766be9c324fa47fb4832399b34db5a186276&lt;/li&gt;&lt;li&gt;# back track until you find the pack that contains the commit&lt;/li&gt;&lt;li&gt;cd /git/path-to-git-dir/objects/pack&lt;/li&gt;&lt;li&gt;cp /untarred-repo/objects/pack/...{idx,pack} .&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-2746069048607008306?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/2746069048607008306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/10/gerrit-code-review-unpack-error-missing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2746069048607008306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2746069048607008306'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/10/gerrit-code-review-unpack-error-missing.html' title='Gerrit Code Review - Unpack error Missing unknown'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-7012346097168588118</id><published>2011-10-26T14:14:00.000-07:00</published><updated>2011-10-26T14:14:50.733-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='registers'/><category scheme='http://www.blogger.com/atom/ns#' term='VIM'/><title type='text'>Vim Registers Current File Name</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;So you guys may remember how I was all obsessed with vim registers a few months ago. Well, today I was typing away at some things and while in insert mode, I wanted to splat the name of the file I was currently editing. So I took a risk:&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Ctrl+R % &amp;nbsp; &amp;nbsp; # i.e. Access register %, which holds the name of the current file.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;result: the name of the file pasted in!&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Pretty cool.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-7012346097168588118?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/7012346097168588118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/10/vim-registers-current-file-name.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7012346097168588118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7012346097168588118'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/10/vim-registers-current-file-name.html' title='Vim Registers Current File Name'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-3327316261814800788</id><published>2011-09-27T23:33:00.006-07:00</published><updated>2011-11-02T13:59:51.418-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='function'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='subshell'/><category scheme='http://www.blogger.com/atom/ns#' term='return'/><category scheme='http://www.blogger.com/atom/ns#' term='gotcha'/><category scheme='http://www.blogger.com/atom/ns#' term='error'/><category scheme='http://www.blogger.com/atom/ns#' term='exit'/><title type='text'>Bash Function Return Values and Exit</title><content type='html'>For those lucky souls out there programming in bash, you may be making use of the bash subshell trick that allows you to "return" a value from a function.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:bash"&gt;function echoTwice() {&lt;br /&gt;  echo "$1"&lt;br /&gt;  echo "$1"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;declare twice=$(echoTwice "woot")&lt;br /&gt;echo "Twice is: $twice"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Will produce the output,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Twice is: woot woot&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The tricky gotcha in this situation involves exiting on error conditions. For example, consider the following enhancement to echoTwice,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:bash"&gt;function echoTwice() {&lt;br /&gt;  if [ -z "$1" ]; then&lt;br /&gt;    echo "Must provide an argument" &amp;gt;&amp;amp;2&lt;br /&gt;    exit 1&lt;br /&gt;  fi&lt;br /&gt;&lt;br /&gt;  echo "$1"&lt;br /&gt;  echo "$1"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;declare twice=$(echoTwice)&lt;br /&gt;echo "Twice is: $twice"&lt;/pre&gt;&lt;br /&gt;You would expect to see the error message and nothing else. &amp;nbsp;However, instead you see&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Must provide an argument&lt;br /&gt;Twice is:&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Why does this happen? It happens because the assignment to $twice happens via a subshell. A subshell is spawned to evaluate the result of echoTwice. When that subshell exits early, bash treats it no differently than had the whole function proceded. Subsequently, rather than quitting your code, processing continues when the subshell completes. So, how do you accomodate this in your code without resorting to ugly globals?&lt;br /&gt;&lt;br /&gt;The solution that I have found is to test if $twice was assigned.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:bash"&gt;if [ -z "$twice" ]; then&lt;br /&gt;  # Error message emitted by echoTwice prints to STD_ERR and&lt;br /&gt;  # ...will not be consumed by the sub-shell&lt;br /&gt;  exit 1&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The reason I can't just check the exit status is because &lt;code&gt;declare twice=&lt;/code&gt; is an actual execution and will typically have a valid exit status.&lt;br /&gt;&lt;br /&gt;EDIT (Nov 2nd, 11): It turns out that you can check the return status! The issue is accurately described that &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;declare twice=&lt;/span&gt; has its own exit status, but the exit status arises from the use of the bash built-in "&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;declare&lt;/span&gt;" and NOT from the assignment to the variable (See the "declare" section of&amp;nbsp;&lt;a href="http://www.gnu.org/software/bash/manual/bashref.html#Bash-Builtins"&gt;http://www.gnu.org/software/bash/manual/bashref.html#Bash-Builtins&lt;/a&gt;). &amp;nbsp;So, the solution becomes:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:bash"&gt;declare twice=&lt;br /&gt;twice=$(echoTwice)&lt;br /&gt;if [ $? -ne 0 ]; then&lt;br /&gt;  # Error message emitted by echoTwice prints to STD_ERR and&lt;br /&gt;  # ...will not be consumed by the sub-shell&lt;br /&gt;  exit 1&lt;br /&gt;fi&lt;br /&gt;echo "Twice is: $twice"&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-3327316261814800788?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/3327316261814800788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/09/bash-function-return-values-and-exit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3327316261814800788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3327316261814800788'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/09/bash-function-return-values-and-exit.html' title='Bash Function Return Values and Exit'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-6596490408136555691</id><published>2011-09-16T09:53:00.001-07:00</published><updated>2011-09-16T09:53:26.575-07:00</updated><title type='text'>Don't Lose Your Phone</title><content type='html'>I get lots of credit card offers in the mail and in my email. In my life, I'm probably indirectly responsible for the life of an entire tree just to print all the offers I've received (not to account for the energy expended delivering them, ink for printing, etc.). &amp;nbsp;Today I finally resolved to bring the offers to an end. There is a phone number listed at the bottom of most offers, 1-888-5OPTOUT, which you can call to remove yourself from the list of people agencies will contact with the great deals. According to the FTC, this number is provided by the National Credit Bureau (&lt;a href="http://www.ftc.gov/privacy/protect.shtm"&gt;http://www.ftc.gov/privacy/protect.shtm&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;I called the number and was very shocked at the information it exposed about me via the simple fact of the phone number from which I was calling. Essentially, by identifying my phone number the automated service provided me, with no security challenge at all, my home address and full name. Transcript below:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;NCB: Are you calling from your home phone?&lt;/li&gt;&lt;li&gt;Me: Yes&lt;/li&gt;&lt;li&gt;NCB: Please verify your address. Is it 123 Street Name, Town, State?&lt;/li&gt;&lt;li&gt;Me: Yes&lt;/li&gt;&lt;li&gt;NCM: Is your last name "Plumber"?&lt;/li&gt;&lt;li&gt;Me: Yes&lt;/li&gt;&lt;li&gt;NCM: Is your first name "Joe"?&lt;/li&gt;&lt;li&gt;Me: Yes&lt;/li&gt;&lt;li&gt;NCM: Please enter your SSN&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;After this point, I actually had to provide the information to verify it was me.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, I suppose that knowing someone's phone number may be enough to find their information online already anyway (white pages?), but I was utterly shocked that a service sponsored by the federal government would so easily give your private information away. My conclusion, be extra careful not to lose your phone and don't give your phone number out too willingly.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-6596490408136555691?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/6596490408136555691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/09/dont-lose-your-phone.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6596490408136555691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6596490408136555691'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/09/dont-lose-your-phone.html' title='Don&apos;t Lose Your Phone'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-4034752584651199384</id><published>2011-06-29T09:49:00.003-07:00</published><updated>2011-11-17T15:39:50.343-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Git Unpack Error Over HTTP Fetch</title><content type='html'>&lt;div&gt;Had a problem today with a server fetching the latest changes from our upstream repository over HTTP. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class="brush:bash"&gt;&lt;br /&gt;git fetch origin&lt;br /&gt;error: packfile .git/objects/pack/pack-385ce85680e3c3ff129907559101b9a4544a9da0.pack does not match index&lt;br /&gt;error: packfile .git/objects/pack/pack-385ce85680e3c3ff129907559101b9a4544a9da0.pack cannot be accessed&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I didn't have much luck finding any advice on google, so I thought I'd post my own solution, which was extremely simple! &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class="brush:bash"&gt;&lt;br /&gt;rm  .git/objects/pack/pack-385ce85680e3c3ff129907559101b9a4544a9da0.pack&lt;br /&gt;git gc&lt;br /&gt;git fetch origin&lt;br /&gt;&lt;br /&gt;Getting pack 385ce85680e3c3ff129907559101b9a4544a9da0&lt;br /&gt;which contains dcbe1aa3d3e564aea30acc55a7df105bfdc586a2&lt;br /&gt;# success&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Essentially, in the version of git we run (1.6.3.1), git fetch over HTTP will blindly pull down every pack regardless of whether or not it is applicable to the downstream checkout. What was happening was the pack somehow got corrupted and an unfetched pack was dependent on that corrupted pack, so git couldn't resolve the mismatch. Removing the corrupted pack let git re-fetch it and the dependent pack that followed.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-4034752584651199384?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/4034752584651199384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/06/git-unpack-error-over-http-fetch.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4034752584651199384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4034752584651199384'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/06/git-unpack-error-over-http-fetch.html' title='Git Unpack Error Over HTTP Fetch'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-2160363345669912239</id><published>2011-05-22T22:46:00.006-07:00</published><updated>2011-11-09T21:09:56.715-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='caltrain'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='applescript'/><category scheme='http://www.blogger.com/atom/ns#' term='cron'/><title type='text'>Don't Miss the CalTrain</title><content type='html'>&lt;div&gt;I have a bad track record of getting to the CalTrain stop on time. It's a very depressed experience to see the train receding into the distance as I race around the curve to the train stop on my bike. It's even more depressing to instead see the train loading, sprint down the stairs, under the track, and back up the other side (all the while carrying my bike rather than  riding down the ramp), and get close enough to touch the train as the conductor closes the doors before I can get in and &lt;i&gt;then &lt;/i&gt;watch the train recede into the distance as I stand there panting.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's clear that the CalTrain expects us to always be on time and shows no quarter. Why? Well because the CalTrain is &lt;i&gt;always &lt;/i&gt;on time. Isn't it? Actually, no, it's not. For one reason or another, the CalTrain can be as much as an hour late, full, or even canceled. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As passengers, we need to be prepared and in the know.  So far, the best resources I've found for being on time and keeping tabs on CalTrain delays are a clock and twitter.com.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The programmer in me hates manual labor, so I decided to automate a little system to help me out. It comes in two parts, &lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;A script to (a) check twitter for tweets @caltrain and (b) make my computer speak and pop up a dialog box with the tweets reminding me to pack up and go catch the train&lt;/li&gt;&lt;li&gt;A schedule to run the script at the same time every day, just in time to catch the train&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The script itself comes in two parts, AppleScript and Ruby. The AppleScript to hook into my Finder app for the dialog box. The Ruby to parse Twitter's API so that I don't have to do it in AppleScript (shudder). &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've posted the scripts up on &lt;a href="https://github.com/asheepapart/caltrain"&gt;github&lt;/a&gt;. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The following pages helped me out:&lt;/div&gt;Ruby JSON - http://flori.github.com/json/&lt;br /&gt;&lt;div&gt;Twitter Search - http://search.twitter.com/api/&lt;/div&gt;&lt;div&gt;AppleScript - http://www.tee-boy.com/forums/viewtopic.php?f=8&amp;amp;t=76&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-2160363345669912239?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/2160363345669912239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/05/dont-miss-caltrain.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2160363345669912239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2160363345669912239'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/05/dont-miss-caltrain.html' title='Don&apos;t Miss the CalTrain'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-3613133861564133364</id><published>2011-04-06T10:19:00.004-07:00</published><updated>2011-04-06T13:58:22.184-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='profile'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='rc'/><category scheme='http://www.blogger.com/atom/ns#' term='prompt'/><category scheme='http://www.blogger.com/atom/ns#' term='local'/><category scheme='http://www.blogger.com/atom/ns#' term='script'/><title type='text'>MySQL.rc Configuring Your MySQL Client</title><content type='html'>I recently wanted to customize the SQL command line prompt so that I'd know the database server to which I was connected. Previously, I'd been using the &lt;span class="Apple-style-span"&gt;--prompt&lt;/span&gt; option when connecting (e.g. &lt;span class="Apple-style-span"&gt;alias dev-db='mysql -h dev-db --prompt "dev-db-mysql&amp;gt;"';&lt;/span&gt;), but that gets maintenance heavy as I add more and more databases to my shortcuts.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I resolved to find a more generic way. I tried all sorts of google searches, all of which came up unhelpful. With no choice left, I headed to the MySQL docs. After some clicking around, I came upon this page, http://dev.mysql.com/doc/refman/5.0/en/mysql-commands.html. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is great news! Apparently, I have several options. &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;/etc/my.cnf&lt;/span&gt; - Globally change the mysql client for all users of a given machine&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;~/.my.cnf&lt;/span&gt; &lt;/span&gt;- Change for just me on a given machine&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;export $MYSQL_PS1&lt;/span&gt; - Change just my prompt without requiring any new files&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Since all of the machines I use are already controlled with puppet, it was a simple change for me to add a definition for $MYSQL_PS1 in my profile. &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-3613133861564133364?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/3613133861564133364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/04/mysqlrc-configuring-your-mysql-client.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3613133861564133364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3613133861564133364'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/04/mysqlrc-configuring-your-mysql-client.html' title='MySQL.rc Configuring Your MySQL Client'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-5729075504951129039</id><published>2011-03-25T21:44:00.004-07:00</published><updated>2011-11-09T21:10:37.192-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='array'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='element_of'/><title type='text'>Element in Array with Bash?</title><content type='html'>I recently found myself editing a rather long conditional evaluation in Bash that was essentially comparing a variable, $color, against several valid matches. If $color didn't match any of them, the condition evaluated to true. I was a little disappointed with the prospect of maintaining it and the stretch of ORs and ==s across my screen. In a "real" scripting language, I would just use an array and check if $color was an element. Then I realized that Bash lets me use an array, just a little differently. With a combination of echo and grep, I got the job done.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre class="brush:bash"&gt;&lt;br /&gt;declare -a valid_colors=( 'green' 'red' 'blue' )&lt;br /&gt;&lt;br /&gt;echo "${valid_colors[@]}" | grep -qv "$color"&lt;br /&gt;if [ $? -eq 0 ]; then&lt;br /&gt;  # Do your stuff&lt;br /&gt;fi&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-5729075504951129039?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/5729075504951129039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/03/element-in-array-with-bash.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5729075504951129039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5729075504951129039'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/03/element-in-array-with-bash.html' title='Element in Array with Bash?'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-4445563899707097506</id><published>2011-03-08T18:19:00.005-08:00</published><updated>2011-11-09T23:00:58.462-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ref-log'/><category scheme='http://www.blogger.com/atom/ns#' term='amend'/><category scheme='http://www.blogger.com/atom/ns#' term='delete'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Oh Shit! Git Amend Ate My Changes!</title><content type='html'>&lt;div&gt;Today a developer did a git commit --amend and accidentally overwrote his entire HEAD. (I'm not sure how, but it did happen.) I knew that since git saves (what seems like) everything, if we could find the commit hash for his previous HEAD that we'd be able to cherry-pick it. We scrolled up through his terminal but couldn't find any reference to it =/ So that meant we needed to try finding it the hard way: .git/&lt;/div&gt;&lt;br /&gt;&lt;div&gt;So then I started looking through the git-dir and after a little digging, we found therein a log file for each branch (&lt;span class="Apple-style-span" style="font-size: 11px;"&gt;&lt;span class="Apple-style-span"&gt;.git/logs/refs/heads/*&lt;/span&gt;&lt;/span&gt;), the contents of which lists the last several commit hashes made to the branch respectively. Alright! Each file contains a somewhat chronological list of the hashes generated by each change to the tree (rebase, pull, commit, cherry-pick, etc.). We were able to use git show on the hashes near the end of our branch's log file and recover the change!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Conclusion, steps to recover:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;git branch -- # e.g. my-feature&lt;/li&gt;&lt;li&gt;tail .git/logs/refs/heads/my-feature&lt;/li&gt;&lt;li&gt;git show $hash # using the hashes from the log file until you find the one you want&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;b&gt;UPDATE:&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;So it turns out the easiest way to do this is to use git reflog, which will list all the changes to your HEAD for the past X changes. &lt;i&gt;Way easier!&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-4445563899707097506?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/4445563899707097506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/03/oh-shit-git-amend-ate-my-changes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4445563899707097506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4445563899707097506'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/03/oh-shit-git-amend-ate-my-changes.html' title='Oh Shit! Git Amend Ate My Changes!'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-5205040599355886118</id><published>2011-03-07T11:48:00.009-08:00</published><updated>2011-11-09T21:13:13.292-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='escape sequence'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='color'/><category scheme='http://www.blogger.com/atom/ns#' term='ps1'/><category scheme='http://www.blogger.com/atom/ns#' term='concatenate'/><title type='text'>Bash PS1 Colors and More Space</title><content type='html'>&lt;pre class="brush:bash"&gt;function prompt_color() {&lt;br /&gt;local gr='\033[0;32m' # light green&lt;br /&gt;local red='\033[0;31m' # light red&lt;br /&gt;local bold_red='\033[1;31m';&lt;br /&gt;&lt;br /&gt;if [ $1 -ne 0 ]; then&lt;br /&gt;  echo -e "${bold_red}**${1}**${red}"&lt;br /&gt;  return&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;echo -e "$gr"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function prompt() {&lt;br /&gt;local nc='\033[0m' # no color&lt;br /&gt;&lt;br /&gt;# User@{2 part hostname} date time directory\nCommand Number $ - me, # - root&lt;br /&gt;# __git_ps1 - show current git branch; http://blog.jasonmeridth.com/2010/05/22/git-ps1.html&lt;br /&gt;local $ps1='[\u@$SHORTNAME \D{%Y-%m-%d} \t \W$(__git_ps1 " (%s)" 2&amp;gt;/dev/null)]'&lt;br /&gt;&lt;br /&gt;export PS1=$(echo '$(prompt_color $?)' "'$ps1'" "$nc" ' \n[\!]\$ ');&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I also employ `echo` above in order to concatenate the color variables with the PS1 string, which should be evaluated ONLY per PS1, not at the time of definition. I originally was using double quotes to surround the entire thing, but then realized that `git_ps1` was getting executed ONLY when PS1 was being defined.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-f72YjPUHU00/TZLAy2cBHII/AAAAAAAAAfw/qGkfyVXMHuQ/s1600/Screen%2Bshot%2B2011-03-29%2Bat%2B10.32.45%2BPM.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5589742067359227010" src="http://1.bp.blogspot.com/-f72YjPUHU00/TZLAy2cBHII/AAAAAAAAAfw/qGkfyVXMHuQ/s320/Screen%2Bshot%2B2011-03-29%2Bat%2B10.32.45%2BPM.png" style="cursor: hand; cursor: pointer; height: 138px; margin: 0 0 10px 10px; width: 320px;" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-5205040599355886118?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/5205040599355886118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/03/bash-ps1-colors-and-more-space.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5205040599355886118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5205040599355886118'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/03/bash-ps1-colors-and-more-space.html' title='Bash PS1 Colors and More Space'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-f72YjPUHU00/TZLAy2cBHII/AAAAAAAAAfw/qGkfyVXMHuQ/s72-c/Screen%2Bshot%2B2011-03-29%2Bat%2B10.32.45%2BPM.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-939917954537392942</id><published>2011-02-04T23:46:00.006-08:00</published><updated>2011-11-17T15:40:43.327-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='color'/><category scheme='http://www.blogger.com/atom/ns#' term='CLI'/><title type='text'>Add Color to PHP Echo in CLI</title><content type='html'>I adapted this PHP script from &lt;a href="http://www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/"&gt;If Not True Then False&lt;/a&gt; for CentOS escape codes, which use a semi-colon and not a comma between bold and color codes for foreground color escaping. &lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: php"&gt;&lt;br /&gt;/**&lt;br /&gt; * Color escapes for bash output&lt;br /&gt; */&lt;br /&gt;class Escape_Colors&lt;br /&gt;{&lt;br /&gt; private static $foreground = array(&lt;br /&gt;  'black' =&amp;gt; '0;30',&lt;br /&gt;  'dark_gray' =&amp;gt; '1;30',&lt;br /&gt;  'red' =&amp;gt; '0;31',&lt;br /&gt;  'bold_red' =&amp;gt; '1;31',&lt;br /&gt;  'green' =&amp;gt; '0;32',&lt;br /&gt;  'bold_green' =&amp;gt; '1;32',&lt;br /&gt;  'brown' =&amp;gt; '0;33',&lt;br /&gt;  'yellow' =&amp;gt; '1;33',&lt;br /&gt;  'blue' =&amp;gt; '0;34',&lt;br /&gt;  'bold_blue' =&amp;gt; '1;34',&lt;br /&gt;  'purple' =&amp;gt; '0;35',&lt;br /&gt;  'bold_purple' =&amp;gt; '1;35',&lt;br /&gt;  'cyan' =&amp;gt; '0;36',&lt;br /&gt;  'bold_cyan' =&amp;gt; '1;36',&lt;br /&gt;  'white' =&amp;gt; '1;37',&lt;br /&gt;  'bold_gray' =&amp;gt; '0;37',&lt;br /&gt; );&lt;br /&gt;&lt;br /&gt; private static $background = array(&lt;br /&gt;  'black' =&amp;gt; '40',&lt;br /&gt;  'red' =&amp;gt; '41',&lt;br /&gt;  'magenta' =&amp;gt; '45',&lt;br /&gt;  'yellow' =&amp;gt; '43',&lt;br /&gt;  'green' =&amp;gt; '42',&lt;br /&gt;  'blue' =&amp;gt; '44',&lt;br /&gt;  'cyan' =&amp;gt; '46',&lt;br /&gt;  'light_gray' =&amp;gt; '47',&lt;br /&gt; );&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Make string appear in color&lt;br /&gt;  */&lt;br /&gt; public static function fg_color($color, $string)&lt;br /&gt; {&lt;br /&gt;  if (!isset(self::$foreground[$color]))&lt;br /&gt;  {&lt;br /&gt;   throw new Exception('Foreground color is not defined');&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return "\033[" . self::$foreground[$color] . "m" . $string . "\033[0m";&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Make string appear with background color&lt;br /&gt;  */&lt;br /&gt; public static function bg_color($color, $string)&lt;br /&gt; {&lt;br /&gt;  if (!isset(self::$background[$color]))&lt;br /&gt;  {&lt;br /&gt;   throw new Exception('Background color is not defined');&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return "\033[" . self::$background[$color] . 'm' . $string . "\033[0m";&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * See what they all look like&lt;br /&gt;  */&lt;br /&gt; public static function all_fg()&lt;br /&gt; {&lt;br /&gt;  foreach (self::$foreground as $color =&amp;gt; $code)&lt;br /&gt;  {&lt;br /&gt;   echo "$color - " . self::fg_color($color, 'Hello, world!') . PHP_EOL;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * See what they all look like&lt;br /&gt;  */&lt;br /&gt; public static function all_bg()&lt;br /&gt; {&lt;br /&gt;  foreach (self::$background as $color =&amp;gt; $code)&lt;br /&gt;  {&lt;br /&gt;   echo "$color - " . self::bg_color($color, 'Hello, world!') . PHP_EOL;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-939917954537392942?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/939917954537392942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/02/add-color-to-php-echo-in-cli.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/939917954537392942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/939917954537392942'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/02/add-color-to-php-echo-in-cli.html' title='Add Color to PHP Echo in CLI'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-7790856452453490258</id><published>2011-01-31T17:24:00.002-08:00</published><updated>2011-11-17T15:40:14.365-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='openSUSE'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='nginx'/><category scheme='http://www.blogger.com/atom/ns#' term='passenger'/><title type='text'>Passenger Root Directive Not Found</title><content type='html'>&lt;div&gt;Error: &lt;/div&gt;&lt;div&gt;&lt;div&gt;nginx: [emerg]: unknown directive "passenger_root" in /box/etc/nginx/nginx.conf:18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Solution:&lt;/div&gt;http://markmail.org/message/ektzyf3hm3oyz5un#query:related%3Aektzyf3hm3oyz5un+page:1+mid:i5hukr2cemguxvtj+state:results&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Two versions of nginx were installed on my openSUSE box. I believe this was because I had already installed it before running the passenger installation script. I may try running it again and telling it to install the new version into the proper path. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-7790856452453490258?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/7790856452453490258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2011/01/passenger-root-directive-not-found.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7790856452453490258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7790856452453490258'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2011/01/passenger-root-directive-not-found.html' title='Passenger Root Directive Not Found'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-5037916934317352410</id><published>2010-12-15T21:43:00.004-08:00</published><updated>2010-12-15T21:52:57.404-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='History'/><category scheme='http://www.blogger.com/atom/ns#' term='VIM'/><title type='text'>VIM Command Line History Window</title><content type='html'>Ever been recording a macro when all of a sudden an unexpected window pops up out of nowhere in the bottom of your window, the contents of which appear to resemble the last few commands you've typed? &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well, it's definitely happened to me. This isn't exactly the sort of thing for which you can search online -- what sort of query can succinctly describe that? Well, today as part of another quest, I finally discovered what's going on! &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;VIM supports command line history (as can be most easily observed by pressing up or down in command line mode, or just typing ":history"). What I didn't know was that when in Command Mode, typing "q:" will open your command history in a sub-window. You can then navigate this window, make changes (in Normal mode), and re-execute the original commands or (and this is the cool part) modified commands simply by pressing enter! (from Command Mode). &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To exit out of the sub-window, just CTRL+C (twice) as you would to cancel out of Command Line mode.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-5037916934317352410?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/5037916934317352410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/12/vim-command-line-history-window.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5037916934317352410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/5037916934317352410'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/12/vim-command-line-history-window.html' title='VIM Command Line History Window'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-6655952605346473179</id><published>2010-11-15T12:38:00.013-08:00</published><updated>2010-11-15T13:13:13.478-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tar'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>Ignore Missing Files with tar</title><content type='html'>I've been experiencing an annoying problem with tar in which it is not creating archives if at least one file in the tar list does not exist.  This behavior is totally acceptable and appreciated when I am tarring on demand.  However, in this case, I am running a command across several machines each of which will have a different sample of a set of files and I need this done as a cron. And to make matters more complicated the file set involves specific files in a set of directories.&lt;div&gt;&lt;pre class="brush: bash"&gt;# The novice command&lt;br /&gt;bash$ tar cfz yesterday-logs.tgz \&lt;br /&gt;log-type1/log-type1-2011-11-15.log \&lt;br /&gt;log-type2/log-type2-2011-11-15.log \&lt;br /&gt;log-type3/log-type3-2011-11-15.log \&lt;br /&gt;log-type4/log-type4-2011-11-15.log&lt;br /&gt;&lt;/pre&gt;This command will work fine if all the directories exist.  However, if at least one of the directories or files does not exist, I will experience the following error and an empty tar archive. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: monospace; font-size: 13px; white-space: pre; "&gt;tar: log-type3/log-type3-2011-11-15.log: Cannot stat: No such file or directory&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: monospace; font-size: 13px; white-space: pre; "&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace; font-size: 13px; white-space: pre; "&gt;tar: Error exit delayed from previous errors.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I solved this issue by using the wonders bash expansion, sub-shell, and std error redirection&lt;/div&gt;&lt;div&gt;&lt;pre class="brush: bash"&gt;bash$ tar cfz yesterday-logs.tgz $( ls log-type{1,2,3,4}/*-2011-11-15.log} 2&gt;/dev/null )&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Fun. I suppose there is most likely a flag to tar that I couldn't find in my scan of the manual entry that completely obviate this complexity, but in the meantime...&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-6655952605346473179?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/6655952605346473179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/11/ignore-missing-files-with-tar.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6655952605346473179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6655952605346473179'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/11/ignore-missing-files-with-tar.html' title='Ignore Missing Files with tar'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-7651995113042860164</id><published>2010-10-17T22:52:00.004-07:00</published><updated>2011-11-17T15:39:30.521-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Gems'/><category scheme='http://www.blogger.com/atom/ns#' term='Yum'/><title type='text'>Update Ruby Gems - CentOS</title><content type='html'>Circular dependencies suck.  It's a really great thing that the entire package management system for Ruby is written with Ruby, until you need to update Ruby using said system when said system itself needs to be updated.  &lt;br /&gt;&lt;br /&gt;I'm currently trying to update Ruby and RubyGems on CentOS via yum and life has not been fun.  Step 1, rubygems wasn't present, so I installed with yum.  That went fine, except it installed version 0.9.2 of gems.  Hmm, Ok, no big deal, I can run gem update --system.  Nope, fail:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;me@host$ sudo gem update ruby&lt;br /&gt;Updating installed gems...&lt;br /&gt;ERROR:  While executing gem ... (Gem::RemoteSourceException)&lt;br /&gt;    HTTP Response 302&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Great, rubygems changed their URL since 0.9.2 and apparently whatever http tool gems uses can't follow redirects.  Well, after some debugging and total failure to find any help online, I discovered that gems maintains a sources file &lt;code&gt;/usr/lib/ruby/gems/1.8/gems/sources-0.0.1/lib/sources.rb&lt;/code&gt; that lists the domain(s) of its repositories.  Well, let me just change that to the new URL&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;module Gem&lt;br /&gt;  @sources = ["http://rubygems.org"]&lt;br /&gt;  def self.sources&lt;br /&gt;    @sources&lt;br /&gt;  end &lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I ran the command again.  STILL getting the 302.  What the heck??? Alright, after some more debugging, I discover it's trying to download a yaml description file located at http://rubygems.org/yaml.  This loads fine in my browser, but a little telnet shows that I'm being redirected (obvious hint from the 302 earlier).  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[me@host]$ telnet rubygems.org 80&lt;br /&gt;Trying 72.4.120.124...&lt;br /&gt;Connected to rubygems.org (72.4.120.124).&lt;br /&gt;Escape character is '^]'.&lt;br /&gt;GET /yaml HTTP/1.1&lt;br /&gt;host: rubygems.org&lt;br /&gt;&lt;br /&gt;HTTP/1.1 302 Found&lt;br /&gt;Date: Mon, 18 Oct 2010 05:46:40 GMT&lt;br /&gt;Server: Apache/2.2.3 (Red Hat) mod_ssl/2.2.3 OpenSSL/0.9.8e-fips-rhel5 Phusion_Passenger/2.2.15&lt;br /&gt;X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.15&lt;br /&gt;X-UA-Compatible: IE=Edge,chrome=1&lt;br /&gt;X-Runtime: 0.000895&lt;br /&gt;Location: http://production.s3.rubygems.org/yaml&lt;br /&gt;Content-Length: 0&lt;br /&gt;Status: 302&lt;br /&gt;Vary: Accept-Encoding&lt;br /&gt;Content-Type: text/html&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hey, look!  There's the redirect URL!  A little update and I'm good to go.  &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;module Gem&lt;br /&gt;  @sources = ["http://production.s3.rubygems.org"]&lt;br /&gt;  def self.sources&lt;br /&gt;    @sources&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then run,&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[me@host]$sudo gem update --system&lt;br /&gt;Updating RubyGems...&lt;br /&gt;Attempting remote update of rubygems-update&lt;br /&gt;Successfully installed rubygems-update-1.3.6&lt;br /&gt;Installing ri documentation for rubygems-update-1.3.6...&lt;br /&gt;Installing RDoc documentation for rubygems-update-1.3.6...&lt;br /&gt;Could not find main page README&lt;br /&gt;Could not find main page README&lt;br /&gt;Could not find main page README&lt;br /&gt;Could not find main page README&lt;br /&gt;Updating version of RubyGems to 1.3.6&lt;br /&gt;Installing RubyGems 1.3.6&lt;br /&gt;ERROR:  Expected Ruby version &amp;gt;= 1.8.6, is 1.8.5&lt;br /&gt;RubyGems system software updated&lt;br /&gt;&lt;br /&gt;### Damn&lt;br /&gt;### Maybe update ruby with gem? &lt;br /&gt;&lt;br /&gt;[me@host]$ sudo gem update ruby&lt;br /&gt;Updating installed gems...&lt;br /&gt;Attempting remote update of ruby&lt;br /&gt;ERROR:  While executing gem ... (Gem::GemNotFoundException)&lt;br /&gt;    Could not find ruby (&amp;gt; 0) in any repository&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nope, no go.  So it looks like I am manually installing Ruby from the source since the yum repository only has Ruby as modern as version 1.8.5 dated 2006-08-25!!    Isn't  Ruby and Rails supposed to make life easier??&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-7651995113042860164?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/7651995113042860164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/10/update-ruby-gems-centos.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7651995113042860164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7651995113042860164'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/10/update-ruby-gems-centos.html' title='Update Ruby Gems - CentOS'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-6093106342751180553</id><published>2010-09-24T15:32:00.007-07:00</published><updated>2010-09-24T16:07:10.599-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTML5'/><category scheme='http://www.blogger.com/atom/ns#' term='Selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='Drop'/><title type='text'>HTML5 Drag and Drop Upload Testing</title><content type='html'>We're building out a testing automation framework at work and one of the most important parts of it involves tests around file uploads.  Historically this has been impossible to automate due to security settings in the browser that disallow setting the file path in a file type input element(e.g. to prevent secretly uploading confidential data from client machines).  However, some browsers now support configurations to allow disabling this restriction for certain websites.  Test automation driver, Selenium, has taken advantage of this and allows a user to set the value of a file type input element.  This works great for the simple case of an explicit form and file type input element.&lt;br /&gt;&lt;br /&gt;Enter HTML5.  Browsers can now respond to the "drop" event and furthermore the XmlHttpRequest specification (http://dev.w3.org/2006/webapi/XMLHttpRequest-2/) has been enhanced to make it possible to programmatically upload a file with javascript (i.e. xhr.send(fileBlob)).  Put those two together and an ambitious web developer can now add automatic drag and drop file uploading to their website.&lt;br /&gt;&lt;br /&gt;This is great for the look and feel of a website, but presents a challenge for the tester: How do I simulate a file drag and drop event?   We were able to solve this issue by skipping the "drag" part and jumping straight to "drop."  What does this mean?  It means that our test will automatically call the "drop" event handler and provide a mock javascript event to the handler.  The handler takes care of creating the xhr and sending it.&lt;br /&gt;&lt;br /&gt;There is still one hurdle to overcome.  The xhr requires an actual File object (http://dev.w3.org/2006/webapi/FileAPI/).  Since it's not possible to create one via standalone javascript, we got around this by creating a new file type input on the page and using Selenium to set its value (a path to a valid file on disk) and then referencing that.&lt;br /&gt;&lt;br /&gt;The following Scala snippet uses jQuery for the dirty work:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: javascript"&gt;&lt;br /&gt;val s = selenium.getEval("fileUpload1 = window.$j('&amp;lt;input/&amp;gt;').attr({type:'file'}).appendTo('body');")&lt;br /&gt;&lt;br /&gt;selenium.text_field("//input[@type='file']").set("path/to/file")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// Trigger the upload event&lt;br /&gt;val mockEventJs = "{originalEvent : {dataTransfer : { files : fileUpload1.get(0).files } } }"&lt;br /&gt;&lt;br /&gt;val ss = selenium.getEval("window.uploader.handle_drop(" + mockEventJs + ")")&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-6093106342751180553?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/6093106342751180553/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/09/html5-drag-and-drop-upload-testing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6093106342751180553'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6093106342751180553'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/09/html5-drag-and-drop-upload-testing.html' title='HTML5 Drag and Drop Upload Testing'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-8027206991234569477</id><published>2010-09-18T16:27:00.003-07:00</published><updated>2010-09-18T17:14:50.309-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Groups'/><category scheme='http://www.blogger.com/atom/ns#' term='Includes'/><category scheme='http://www.blogger.com/atom/ns#' term='Arel'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails 3'/><title type='text'>Arel and Rails 3 - The Rage and Grace</title><content type='html'>&lt;div&gt;I've been spending my time recently rebuilding the front end of a logging system we have to use Rails 3.  This has been a lot of fun and I've come up with some fun code (pagination and naturaldate).  The new ActiveRecord::Relation class has really made my data interactions streamlined and readable -- including (and especially) performant.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unfortunately, I've found that Arel and Rails 3's journey into SQL's GROUP BY clause was a little brief.  While I appreciate ActiveSupport::OrderedHash as a combination of array and hash to effectively express the results of a group by -- and effectively any other such ordered hash data set -- I was frustrated and disappointed by the way it handles multiple properties in the GROUP BY or SELECT clause.  Additionally, I was thrown off for some time before I realized the fact that :count() returns an OrderedHash and not a number when dealing with a :group type active relation.  Perhaps it's my own inability to figure out how to use Rails' or Arel's (poorly (if at all) documented) methods, but I've found that if I want any information outside of a basic &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SELECT COUNT(*), property_name FROM tbl GROUP BY property_name&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;that I am forced to do more than one query.  Hmm, I thought ORM was supposed to make my life easier or at least not make my website slower?  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In my specific case, I need to group by several properties and paginate over the results.  On top of that, I also needed an aggregate result in my select list. Not to mention the pagination parts. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SELECT prop1, prop2, COUNT(prop2) FROM tbl GROUP BY prop1, prop2&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is how I solved it:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;counts = Model.&lt;/div&gt;&lt;div&gt;  select("prop1, prop2, COUNT(prop2) AS 'prop3'). &lt;/div&gt;&lt;div&gt;  group("prop1, prop2")&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;num_pages = counts.all.size&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;page = counts.&lt;/div&gt;&lt;div&gt;   limit(page_size).&lt;/div&gt;&lt;div&gt;  offset(page_num * page_size)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are two important things to notice above as hacks/sadness&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;counts.all.size -- This will query the full set from the database as opposed to COUNT(*)&lt;/li&gt;&lt;li&gt;COUNT(prop2) AS 'prop3' -- Hmm, what?  Since rails will ignore anything in the select list that isn't a property on the referenced model's table, I have to trick into loading my aggregation result into prop3.  Ugly.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;i&gt;Part 2:&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now that all of that is behind me, I'm faced with a new problem!  Rails 3 doesn't support :include with :group!  Oh pain, why can't life be simple?   How did I solve this?  Well, more hackery.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;include() works by creating an instance of the included class and then uses its :find method to load all the referenced records after the initial model's data has been loaded in what might be called lazy loading, but what seems more like 1 + 1 versus N + 1 loads.  Rails is able to programmatically do this in an elegant fashion by loading a reflections property on every ActiveRecord that defines a set of all foreign key relations to the singleton of that foreign key's ActiveRecord (Model) class.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Using this knowledge, I can imitate that same behavior by collecting all the referenced foreign keys in my select class (into :ids) and do the following,&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;fk1_records = Model1.new.reflections[fk1_class_name.to_sym].klass.find(ids)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I can then iterate over the result set and define the relationships accordingly.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-8027206991234569477?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/8027206991234569477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/09/arel-and-rails-3-rage-and-grace.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/8027206991234569477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/8027206991234569477'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/09/arel-and-rails-3-rage-and-grace.html' title='Arel and Rails 3 - The Rage and Grace'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-710163678386003789</id><published>2010-07-27T11:15:00.002-07:00</published><updated>2010-07-27T11:32:59.481-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rails 3'/><title type='text'>mapper.rb:143:in `default_controller_and_action': missing :action (ArgumentError)</title><content type='html'>I'm trying out Rails 3 for a small web project we need done at work.  After spending more time than I wanted yesterday getting everything configured correctly on my Mac (namely mysql 64 bit), I was finally ready to start generating some MVC action.  I followed the steps on the http://guides.rails.info/getting_started.html Rails 3 intro page to generate a controller for my home index.  This added a route to my routes.rb, &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;get "home/index"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I thought I'd get fancy also add a root controller and view for my website, so I coped that and slightly modified it to &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;root :to =&gt; "home/index"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Cool.  Next, I went ahead and tried to generate a new scaffold for my first model, but uh oh, there was a problem!  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/Library/Ruby/Gems/1.8/gems/actionpack-3.0.0.beta4/lib/action_dispatch/routing/mapper.rb:143:in `default_controller_and_action': missing :action (ArgumentError)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;from /Users/.../Code/.../config/routes.rb:2&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;from /Library/Ruby/Gems/1.8/gems/railties-3.0.0.beta4/lib/rails/commands.rb:16&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;from script/rails:6:in `require'&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;from script/rails:6&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My first reaction was, "!@# yet another problem with Rails 3 and my system," but after some searching for the error turned up nothing, I decided that I had probably screwed something up.  Looking a little more closely at the stack trace of the error, I identified that the scaffold generation was in part based on code from my own app and not just the rails gems.  Hmm, probabilities rising that I'm the culprit.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The error says that the default controller is missing an action.  I checked out the gem, mapper.rb, and saw that it's parsing out some variable named "to" for a controller and action.  I then opened up my routes.rb and saw that line of copied code, root :to =&gt; "home/index".  I then thought back to the new rails syntax that I'd learned in the video tutorials and immediately realized my folly.  One quick change, &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;root :to =&gt; "home#index"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and the generator is back to working.  Although it can definitely be a pain dealing with open source software, it certainly is nice to be able to see the source of your problems.    &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-710163678386003789?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/710163678386003789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/07/mapperrb143in-defaultcontrollerandactio.html#comment-form' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/710163678386003789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/710163678386003789'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/07/mapperrb143in-defaultcontrollerandactio.html' title='mapper.rb:143:in `default_controller_and_action&apos;: missing :action (ArgumentError)'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-3308726005255456992</id><published>2010-07-07T18:01:00.007-07:00</published><updated>2011-11-17T15:41:00.173-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Migrating from svn to git</title><content type='html'>Several tutorials have already documented the necessary steps for the conversion from svn to git (&lt;a href="http://www.gitready.com/beginner/2009/02/04/converting-from-svn.html"&gt;http://www.gitready.com/beginner/2009/02/04/converting-from-svn.html&lt;/a&gt;), so I won't reiterate any of that.   What made our migration tricky were two things: &lt;br /&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;SVN commits without authors&lt;/li&gt;&lt;li&gt;No tags, branches, or trunk paths&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The second was easy to fix actually.  I didn't specify any flags for standard layout or tags/branches in the git svn clone command.  The second took a little bit of guess work.  Before I begin, I'll point out that I used the script (after cleaning up the leading and trailing white space)&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;svn -q log | grep ^r | cut -d '|' -f 2 | sort | uniq &amp;gt; authors.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;as conveniently provided in the comments to one of the tutorials.   Just to make life easy, I used the following VI macro to fill out the definitions in the file, &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; yeA= ^[pa &amp;lt;^[pa@domain.com&amp;gt;^[j0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I noticed a blank line in the file, which was generated because of commits to the repo with no user name -- literally just the empty string.  Big deal, I just removed it.  When I tried to run the "git svn clone" though, it puked when it got to those revisions:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&amp;gt;git svn clone svn://svn.domain/project -A authors.txt&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Author: (no author) not defined in authors.txt file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I googled and found a support article, &lt;a href="http://support.github.com/discussions/repos/2690-authors-not-defined-on-svn-import"&gt;http://support.github.com/discussions/repos/2690-authors-not-defined-on-svn-import&lt;/a&gt;, which didn't actually solve the problem, just avoided it.  It turned out the fix was actually easier than I thought.  I added the following line to the authors file: &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;(no author) = no_author &lt;dev_null@domain.com&gt;&lt;/dev_null@domain.com&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-3308726005255456992?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/3308726005255456992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/07/migrating-from-svn-to-git.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3308726005255456992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3308726005255456992'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/07/migrating-from-svn-to-git.html' title='Migrating from svn to git'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-6020656132771218085</id><published>2010-06-14T11:19:00.001-07:00</published><updated>2011-11-17T15:39:04.246-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VIM'/><title type='text'>Great List of VIM Tricks</title><content type='html'>&lt;a href="http://www.slideshare.net/ZendCon/vim-for-php-programmers-presentation"&gt;http://www.slideshare.net/ZendCon/vim-for-php-programmers-presentation&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-6020656132771218085?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/6020656132771218085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/06/great-list-of-vim-tricks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6020656132771218085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/6020656132771218085'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/06/great-list-of-vim-tricks.html' title='Great List of VIM Tricks'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-2842646651225278560</id><published>2010-03-16T15:08:00.005-07:00</published><updated>2011-11-17T15:41:18.852-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IntelliJ'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><category scheme='http://www.blogger.com/atom/ns#' term='VIM'/><title type='text'>IdeaVIM in IntelliJ Community Edition</title><content type='html'>So, I started using IntelliJ last month and I've really been enjoying it.  As a previous heavy user of ReSharper with Visual Studio, I've grown accustomed to the convenience and efficiency of an IDE with refactoring and code inspection built in.   However, I immediately began to suffer from the lack of VI keybindings.  &lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One of the great things about IntelliJ is the huge repository of plugins.  To top that off, the plugins are integrated right into the preferences manager so you can search, download, and enable them all in one easy place.    My search in the plugins manager came up empty, so I continued the search online where I did find a plugin listed right on the IntelliJ website!  IdeaVIM: &lt;a href="http://plugins.intellij.net/plugin/?id=164"&gt;http://plugins.intellij.net/plugin/?id=164&lt;/a&gt;.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why wasn't it showing up in my plugins manager?  Well, it turns out that the IdeaVIM plugin is only offered to users of the IntelliJ Ultimate edition.  Great... I'm not about to pay $250 to get key bindings for one of the most prevalent text editors in the world in my IntelliJ, on top of the fact that the money doesn't go directly to the plug-in developer (Note, I was happy to pay $60 for my copy of &lt;a href="http://www.viemu.com/"&gt;ViEmu&lt;/a&gt;).   &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So two things happened next that got me what I needed, &lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;I saw a "download" link on the plug-ins page&lt;/li&gt;&lt;li&gt;I learned that my coworker had successfully installed the plugin on his computer before they restricted it to the Ultimate edition&lt;/li&gt;&lt;/ol&gt;With that knowledge in hand, I was ready to try a new tactic:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;I downloaded and unzipped the plugin and placed it in my &lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;~/Library/Application Support/IntelliJIdea90CE/&lt;/span&gt; directory.  &lt;/li&gt;&lt;li&gt;Next, I copy-and-pasted the &lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;availables.xml&lt;/span&gt; configuration section for the IdeaVIM plugin off my coworker's computer into my own.  &lt;/li&gt;&lt;li&gt;Then I restarted IntelliJ and ta-da, I now have VIM!  &lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-2842646651225278560?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/2842646651225278560/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/03/ideavim-in-intellij-community-edition.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2842646651225278560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2842646651225278560'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/03/ideavim-in-intellij-community-edition.html' title='IdeaVIM in IntelliJ Community Edition'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-4917058624179642061</id><published>2010-01-20T15:45:00.004-08:00</published><updated>2010-01-20T15:57:32.671-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Storage'/><category scheme='http://www.blogger.com/atom/ns#' term='Outlook'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows XP'/><title type='text'>Where Does Outlook Keep My Email?</title><content type='html'>My web searches on this topic were helpful, but incomplete.  Our company uses an exchange server to house all of our corporate emails, so technically all of my email is on the exchange server.  For performance, however, my email is also stored locally on my machine in my user's local settings: &lt;span style="font-family: courier new;"&gt;C:\Documents and Settings\%user%\Local Settings\Application Data\Microsoft\Outlook&lt;/span&gt;.   (Don't forget the local settings part.)   This much info I found online. &lt;br /&gt;&lt;br /&gt;The complicated part is that my company just switched to exchange -- I'm not sure what we were using prior -- so I have more than one PST (personal storage) in there.    On a hunch, I checked out my control panel's "Mail" interface. &lt;br /&gt;&lt;ol&gt;&lt;li&gt;Open Control Panel -&gt; Mail&lt;/li&gt;&lt;li&gt;Click E-mail Accounts&lt;/li&gt;&lt;li&gt;Switch to tab "Data Files"&lt;/li&gt;&lt;li&gt;The path to the PST file for my current profile is right there!&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;That was easy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-4917058624179642061?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/4917058624179642061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2010/01/where-does-outlook-keep-my-email.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4917058624179642061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4917058624179642061'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2010/01/where-does-outlook-keep-my-email.html' title='Where Does Outlook Keep My Email?'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-7418171126360500519</id><published>2009-12-29T12:50:00.005-08:00</published><updated>2009-12-29T13:30:39.648-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Bytes'/><category scheme='http://www.blogger.com/atom/ns#' term='Bits'/><title type='text'>Bit (not Byte) Manipulation in Ruby</title><content type='html'>I was recently tasked with creating a rough version of the Lempel-Ziv 77 encoder/decoder engine for use in most operating systems (i.e. Windows, Linux, Mac). The application would need to read a binary file and compress it or decompress it to another binary file. The compression algorithm involved a format bit specifying compressed or literal bytes to follow and then distance and length bits of instructions for compressed data. Such an application would clearly involve a good deal of bit manipulation and consequently require a solid bit manipulation library.&lt;br /&gt;&lt;br /&gt;The logical language of choice to me was C++ because of its proximity to the memory, inherent ease of bit manipulation, and presence on every computer since I was born. Unfortunately, I can probably barely compile a "hello, world!" application in C++ =( Next I considered Java since it's open source and present on most people's computers. However, my Java skillz have sadly dwindled since college to the point that I frustratingly discarded that project about an hour after I started. Finally, I decided upon Ruby as my language of choice -- mainly because I like coding in Ruby.&lt;br /&gt;&lt;br /&gt;My project got off to a good start until I realized that the original research I'd done on manipulating bits in Ruby had been incomplete. Ruby inherently manages characters and bytes synonymously, but bits are another story. Based on the loose typing model of Ruby, any use of bits throughout my code was being converted to their numeric string representation behind the scenes. For example, 0xff was ending up as the string "255" when I was writing it to a file.&lt;br /&gt;&lt;br /&gt;Finally, after much worrying, reading of documentation, online research, and irb investigation, I had an answer.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Bytes can be specified in Ruby per bit as such, 255 = 0b1111_1111 (each four bits are separated by an underscore). This was important for me since I was doing a lot of shifting and didn't want to worry about the actual numerical values in my unit testing.&lt;/li&gt;&lt;li&gt;Bytes can be written explicitly to files in Ruby using the &amp;lt;&amp;lt; operator along with Array.pack. &lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: courier new;font-family:courier new;" &gt;File.open("foo.txt", "wb+") { |f| f &amp;lt;&amp;lt; [0xff].pack("c") }&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Bytes can be easily read using &lt;span style="font-family:courier new;"&gt;File.each_byte&lt;/span&gt;&lt;/li&gt;&lt;li&gt;The byte code for a given character can be accessed using: &lt;span style="font-family:courier new;"&gt;"a"[0]&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Binary file manipulation involving windows &lt;span style="font-style: italic;"&gt;must &lt;/span&gt;be done using the "b" flag when opening the file.  Otherwise, the windows file system will treat certain bytes as termination characters and ignore the remainder of the file.   I learned this the hard way because &lt;span style="font-family:courier new;"&gt;each_byte&lt;/span&gt; would just inexplicably stop reading in bytes from my file before the file was finished.&lt;/li&gt;&lt;/ul&gt; After I had all of this figured out, Ruby proved to a very nice environment for writing the app.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-7418171126360500519?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/7418171126360500519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2009/12/bit-not-byte-manipulation-in-ruby.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7418171126360500519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/7418171126360500519'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2009/12/bit-not-byte-manipulation-in-ruby.html' title='Bit (not Byte) Manipulation in Ruby'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-4722489088119987971</id><published>2009-12-29T12:16:00.002-08:00</published><updated>2009-12-29T12:48:32.172-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='templates'/><title type='text'>New Class Templates in C#</title><content type='html'>My team &lt;span style="font-style: italic;"&gt;finally &lt;/span&gt;upgraded to .NET 3.5 along with Visual Studio 2008 recently, which has been a huge source of happiness for me.  However, since the upgrade, I've been getting annoyed with VS's insistence that I always include the Linq library in each of my new classes.  I typically remove all of the default using directives anyway, but since I don't automatically reference the System assembly that contains the Linq definition, I was getting a pre-compile error from R# every time I added a new item to a project.   In addition, I've been growing tired of having to type "public" each time I add a new class (since the default is nothing).   So, I decided to take action.&lt;br /&gt;&lt;br /&gt;A little bit of web searching lead me to the &lt;a href="http://msdn.microsoft.com/en-us/library/ms247064%28VS.80%29.aspx"&gt;Visual Studio Template Reference&lt;/a&gt;.  Each time a new item is created in Visual Studio, VS finds the template definition that matches the item and generates the code to match.  Templates support logical control flow and variable replacement.  By default the C# class templates are  stored in "&lt;span style="font-family:courier new;"&gt;\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplates\CSharp\Code\1033&lt;/span&gt;", with similar templates stored nearby.   The instructions are geared the reader toward creating their own templates for new types of items, which is a very useful tool (but I can do that with resharper), but I really just wanted to change the default.  So I went in and did it: no more "using" and always public.&lt;br /&gt;&lt;br /&gt;Before my changes would take effect, I first had to close visual studio and then run the following command,&lt;br /&gt;&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;devenv /installvstemplates&lt;/blockquote&gt;&lt;br /&gt;which will rebuild the VS templates run-time cache folder.&lt;br /&gt;&lt;br /&gt;Now I can focus on all the fun features of 3.5!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-4722489088119987971?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/4722489088119987971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2009/12/new-class-templates-in-c.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4722489088119987971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/4722489088119987971'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2009/12/new-class-templates-in-c.html' title='New Class Templates in C#'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-2498706962587129313</id><published>2009-12-09T08:49:00.005-08:00</published><updated>2011-11-17T15:41:32.087-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VIM'/><category scheme='http://www.blogger.com/atom/ns#' term='macros'/><title type='text'>VI - Macros</title><content type='html'>Abstracting repetitive steps of work in an on-the-fly macro is a task I find myself doing almost daily during development or database scripting.  After hammering a pretty good one today, I was wondering to myself how to go about saving it.  I did some Google searching ("save vi macro", "copy vi macro"),  but came up empty.  Then I realized that I already knew the answer.  Whenever I record a new vi macro, I record to the q register.  So I knew that my macro must be sitting as plain old text in the q register.  So, I pasted the q register to my screen and lo and behold, there was my macro!   I created a macros text file to track all my commonly used macros with descriptions of what they do.  Yay!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-2498706962587129313?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/2498706962587129313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2009/12/vi-macros.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2498706962587129313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2498706962587129313'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2009/12/vi-macros.html' title='VI - Macros'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-3550277657773020556</id><published>2009-10-12T19:07:00.000-07:00</published><updated>2009-10-12T19:08:24.832-07:00</updated><title type='text'>Tide?</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Tahoma, fantasy; font-size: 12px; white-space: pre; "&gt;&lt;a href="http://www.seafriends.org.nz/oceano/tides.htm"&gt;http://www.seafriends.org.nz/oceano/tides.htm&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:Tahoma, fantasy;font-size:100%;"&gt;&lt;span class="Apple-style-span" style="font-size: 12px; white-space: pre;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-3550277657773020556?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/3550277657773020556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2009/10/tide.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3550277657773020556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/3550277657773020556'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2009/10/tide.html' title='Tide?'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-2043829276401804844</id><published>2009-10-07T20:53:00.003-07:00</published><updated>2011-11-17T15:41:52.688-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Backreference'/><category scheme='http://www.blogger.com/atom/ns#' term='VIM'/><title type='text'>VI and Ruby</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;I've decided it's way past time to get up to speed with Ruby.  After several years of constantly changing my personal idiom for javascript styling due to learning things in pieces, I decided that I would try to learn the Ruby style up front.  The two biggies that I've been offending are,&lt;br /&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;One blank space between comment hash (#) and first character&lt;/li&gt;&lt;li&gt;Spaces &lt;i&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt; (and two of those, btw) &lt;/span&gt;not &lt;/i&gt;tabs&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Since I'm just starting this blog thing, I haven't had the chance yet to mention that I'm a big VI fan.  Naturally, I'm doing my Ruby development in VI.  So, first I needed to make some use of VI's find and replace expression with backreferencing power for #1,&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="color: #009900;"&gt;# Insert a blank space into all comments not beginning with one blank space but be careful to avoid replacing other uses of # (e.g. #{})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="color: #000099;"&gt;:%s/#\(\w\)/# \1/&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nice!  That was easy.  Yet another experience of feeling pretty good about VI.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now on to style tip #2.  Other than the simple search/replace to clean up my existing code, I had to change my tabs to spaces.  Some simple changes to my .vimrc and I was ready to go!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="color: #009900;"&gt;#tab = two spaces&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="color: #000099;"&gt;set tabstop=2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="color: #009900;"&gt;#use spaces and not the tab character&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="color: #000099;"&gt;set expandtab&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-2043829276401804844?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/2043829276401804844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2009/10/vi-and-ruby.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2043829276401804844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/2043829276401804844'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2009/10/vi-and-ruby.html' title='VI and Ruby'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-391002448548932076</id><published>2009-08-21T06:14:00.005-07:00</published><updated>2009-11-04T14:29:03.902-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='missing logs'/><category scheme='http://www.blogger.com/atom/ns#' term='broken'/><category scheme='http://www.blogger.com/atom/ns#' term='log4net'/><title type='text'>log4net: No layout set for the appender named</title><content type='html'>I recently created a new ASP.NET web project and set it up to use &lt;span style="font-family:courier new;"&gt;log4net &lt;/span&gt;with a &lt;span style="font-family:courier new;"&gt;RollingFileAppender&lt;/span&gt; as its logging framework.  However, at first my log file wasn't showing up at all and then after I got it showing up, my log statements were not being written.  Fixing this involved two steps.&lt;br /&gt;&lt;br /&gt;First, the DLL reference generated by Visual Studio did not automatically set the log4net assembly to copy local.  Setting this property on the reference solved the issue of my log file not appearing.&lt;br /&gt;&lt;br /&gt;Second, now that I had my file, I was not seeing any log statements written to it.  Debugging the process, I saw the following error output from log4net:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;AppenderSkeleton: No layout set for the appender named&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Looking at my configuration file, I saw that I &lt;span style="font-style: italic;"&gt;was &lt;/span&gt;setting an appender layout.  However, I noticed that my appender layout was based on a type defined in a different project.  Checking the reference to that project, I again found that Visual Studio was not copying a local version of the assembly, i.e. the &lt;span style="font-family:courier new;"&gt;Private &lt;/span&gt;flag was set to &lt;span style="font-family:courier new;"&gt;false&lt;/span&gt;.   Switching this flag to &lt;span style="font-family:courier new;"&gt;true &lt;/span&gt;fixed the problem and now my logs are showing up!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-391002448548932076?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/391002448548932076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2009/08/log4net-no-layout-set-for-appender.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/391002448548932076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/391002448548932076'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2009/08/log4net-no-layout-set-for-appender.html' title='log4net: No layout set for the appender named'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7398379322753724627.post-9013034908072614260</id><published>2009-08-19T21:12:00.002-07:00</published><updated>2009-08-19T21:33:12.861-07:00</updated><title type='text'>Long Method Names</title><content type='html'>As code completion (or auto complete) has become more ubiquitous and second nature to most software developers, so also has the tendency to spend less time thinking critically about the names that we assign our variables and methods.  In place of this, I have observed the likelihood to squeeze the entire purpose of the variable or method into the name (e.g. DoThisUnlessThatIsTrueAndBeGentle()).  Perhaps we may soon have the entire algorithm of a method squeezed into a name (with the obvious advantage of not needing to read the method at all!).  Have we lost (or forgotten) the advantage of abstracting the purpose of a variable or implementation of a method (or class) behind a simple, distinct name?&lt;br /&gt;&lt;br /&gt;Disadvantages:&lt;br /&gt;1. It's almost never possible to completely and accurately name a variable or method.  Any attempt to do so may lead to more confusion.&lt;br /&gt;2. Side-by-side comparisons of two versions of the same code become more painstaking with horizontal scrolling -- perhaps a bug is even missed because the developer is too lazy/busy to mess with the scrolling.&lt;br /&gt;3. Constrained to multi-line formatting&lt;br /&gt;&lt;br /&gt;Advantages:&lt;br /&gt;1. More descriptive names?&lt;br /&gt;&lt;br /&gt;I am often reminded of an article by Joel Spolsky (back when I read his stuff): &lt;a href="http://www.joelonsoftware.com/articles/Wrong.html"&gt;http://www.joelonsoftware.com/articles/Wrong.html&lt;/a&gt; (scroll to the "I'm Hungary" section towards the bottom) when I ruminate on this subject.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7398379322753724627-9013034908072614260?l=asheepapart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://asheepapart.blogspot.com/feeds/9013034908072614260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://asheepapart.blogspot.com/2009/08/long-method-names.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/9013034908072614260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7398379322753724627/posts/default/9013034908072614260'/><link rel='alternate' type='text/html' href='http://asheepapart.blogspot.com/2009/08/long-method-names.html' title='Long Method Names'/><author><name>Ben</name><uri>http://www.blogger.com/profile/11437593840142482845</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
