<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>ELC Code Feed</title>
    <link>http://elctech.com/</link>
    <description>News, projects, and more.</description>
    <language>en-us</language>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/ElcCodeFeed" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Testing invocation of external executables, %x{}, `</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;If you ever found yourself trying to write tests for code that invokes an external executable, such as:

&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="JEntityNameType"&gt;Beef&lt;span class="EntityInheritedClass"&gt; &lt;span class="EntityInheritedClass"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;diskspace&lt;/span&gt;(&lt;span class="Variable"&gt;flags &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;sh&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)
      &lt;span class="String"&gt;&lt;span class="String"&gt;`&lt;/span&gt;du -&lt;span class="String"&gt;&lt;span class="String"&gt;#{&lt;/span&gt;flags&lt;span class="String"&gt;}&lt;/span&gt;&lt;/span&gt; .&lt;span class="String"&gt;`&lt;/span&gt;&lt;/span&gt;.&lt;span class="Entity"&gt;split&lt;/span&gt;.&lt;span class="Entity"&gt;first&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;
&lt;/p&gt;&lt;/p&gt;
&lt;p&gt;...and wondered how to write a spec that ensures the du command is called with the right options, you might have tried something like:

&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  before &lt;span class="Keyword"&gt;do&lt;/span&gt;
    &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;beef&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Beef&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  it &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;has diskspace with humanized multipliers&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
    &lt;span class="Support"&gt;Kernel&lt;/span&gt;.&lt;span class="Entity"&gt;should_receive&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;`&lt;/span&gt;).&lt;span class="Entity"&gt;with&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;du -h .&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;beef&lt;/span&gt;.&lt;span class="Entity"&gt;diskspace&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;h&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;
&lt;/p&gt;&lt;/p&gt;
&lt;p&gt;That doesn't work.&lt;/p&gt;

&lt;p&gt;After some headscratching and calls for help on the ruby-talk mailing list, I learned how the Kernel#` method is not being called directly. The Ruby object hierarchy has Object at the top-level, and thus all your objects eventually descends from Object. As Object mixes in Kernel, all your objects have all the methods defined in that module, so it's not Kernel that receives your call to "`", but it's the current 'self'. In the example above it's the @beef instance.&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="JEntityNameType"&gt;Sheep&lt;/span&gt;
    &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;mytick&lt;/span&gt;(&lt;span class="Variable"&gt;arg&lt;/span&gt;)
      puts &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;tickety-tick: &lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;arg&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;inspect&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
    &lt;span class="Keyword"&gt;alias&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&amp;quot;&lt;/span&gt;`&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;mytick&lt;/span&gt;

    &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;tick_it!&lt;/span&gt;
      &lt;span class="String"&gt;&lt;span class="String"&gt;`&lt;/span&gt;cheese&lt;span class="String"&gt;`&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  &lt;span class="Support"&gt;Sheep&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;.tick_it!
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  $ ruby sheep.&lt;span class="Entity"&gt;rb&lt;/span&gt;
  tickety&lt;span class="Keyword"&gt;-&lt;/span&gt;tick: &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;cheese&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;&lt;/p&gt;&lt;/p&gt;


&lt;p&gt;So, to test the original code, here's the right way:

&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  it &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;has diskspace with humanized multipliers&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
    &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;beef&lt;/span&gt;.&lt;span class="Entity"&gt;should_receive&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;`&lt;/span&gt;).&lt;span class="Entity"&gt;with&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;du -h .&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;beef&lt;/span&gt;.&lt;span class="Entity"&gt;diskspace&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;h&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;
&lt;/p&gt;&lt;/p&gt;
&lt;p&gt;All of the above also applies to the "%x[]"-syntax (just an alias for Kernel#`).&lt;/p&gt;

&lt;p&gt;Kudos to Brian Chandler for helping out on this, and happy hacking!&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/v7aXIPmvG5E" height="1" width="1"/&gt;</description>
      <author>David Palm</author>
      <pubDate>Thu, 09 Jul 2009 10:17:17 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/v7aXIPmvG5E/testing-invocation-of-external-executables-x</link>
      <guid isPermaLink="false">http://elctech.com/articles/testing-invocation-of-external-executables-x</guid>
    <feedburner:origLink>http://elctech.com/articles/testing-invocation-of-external-executables-x</feedburner:origLink></item>
    <item>
      <title>Solr vs. Sphinx - fuzzy search</title>
      <description>&lt;div class="preface"&gt;
&lt;h2&gt;First the results....&lt;/h2&gt;
&lt;p&gt;Fuzzy search accuracy for commonly misspelled drug names using sphinx and solr with different stemmers&lt;/p&gt;
&lt;img src="http://elccore.s3.amazonaws.com/25/800/search_results.png" alt="Search_results" /&gt;
&lt;/div&gt;
&lt;h2&gt;A little background: &lt;/h2&gt;
&lt;p&gt;We are about to add full text searching to our rails project, and we thought we would take a look a few different solutions for search.  We have been using solr on an older project and were fairly happy with the results, just a little disappointed in the indexing speed.   Also, solr plugins for rails seem to be a little fragmented at this point.  acts_as_solr has no real home other than github where you have to play "pick a fork".  There are a few other libraries for solr (eg. Sunspot) in rails but none of them seem to be mature or very active.  &lt;/p&gt;

&lt;p&gt;We decided to try sphinx with the thinking_sphinx plugin.  Our first impressions seemed to be very good.  Extremely fast indexing, nice support for indexing associated models, and all around very easy to work with as a developer.  But....&lt;/p&gt;

&lt;p&gt;Fuzzy Search:&lt;/p&gt;
&lt;p&gt;We are mostly searching non-English words (eg. last names).  While using sphinx for a little while, we began to "feel" the search results were not as good as they had been in solr.  With search results and open source search tools, your results basically boil down to what &lt;a href="http://en.wikipedia.org/wiki/Stemming" target="_blank"&gt;stemmer&lt;/a&gt; (algorithm) the tools are using to find the relevant results.&lt;/p&gt;

&lt;p&gt;In order to get a quantifiable "score" for search results, I decided to write a little test script that would test the different configurations against a known set of drug names and there common misspellings found &lt;a href="http://www.drugs.com/search-wildcard-phonetic.html" target="_blank"&gt;here&lt;/a&gt;.  The script indexed the properly spelled drug names and then searched using the misspelled name.  If the result was found in the top 10 results it was considered a match.  &lt;/p&gt;

&lt;p&gt;Above are the results using different stemmers (sphinx calls this "morphology" options)  Solr obviously had the best results.&lt;/p&gt;

&lt;p&gt;Solr uses the &lt;a href="http://en.wikipedia.org/wiki/Levenshtein_distance" target="_blank"&gt;Levenshtein&lt;/a&gt; distance by default if you use the "~" fuzzy search operator.  Unfortunately, sphinx does not have the option to use the Levenshtein distance, just soundex, metaphone among others.&lt;/p&gt;

&lt;p&gt;So for now we have decided to move back to Solr and most likely a fork of acts_as_solr.  Any other options out there for rails and solr?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/matMlMogrXY" height="1" width="1"/&gt;</description>
      <author>John Eberly</author>
      <pubDate>Tue, 07 Jul 2009 01:08:22 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/matMlMogrXY/solr-vs-sphinx---fuzzy-search</link>
      <guid isPermaLink="false">http://elctech.com/articles/solr-vs-sphinx---fuzzy-search</guid>
    <feedburner:origLink>http://elctech.com/articles/solr-vs-sphinx---fuzzy-search</feedburner:origLink></item>
    <item>
      <title>Ruby FreshBooks Integration</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;Having trouble integrating FreshBooks? So were we.&lt;/p&gt;

&lt;h2&gt;Some gotchas:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The README is often incorrect.&lt;/li&gt;
&lt;li&gt;Update doesn't work. Use our gem.&lt;/li&gt;
&lt;li&gt;Status for estimates is an integer, not string: 1 draft, 2 sent, 3 viewed, 4 replied
5 accepted, 6 invoiced&lt;/li&gt;
&lt;li&gt;Check the result for invoice.update. If it's false, there's an error. Edit the gem to turn on debug statements around lib/freshbooks/connection.rb:call_api&lt;/li&gt;
&lt;li&gt;To download the pdf, you must set the status to 'sent' for a draft (remember to set it back!).&lt;/li&gt;
&lt;li&gt;Install it: gem install elc-freshbooks.rb --source http://gems.github.com&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Full code to download an invoice or estimate PDF:&lt;/h2&gt;
&lt;/div&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;get_pdf&lt;/span&gt;(&lt;span class="Variable"&gt;inv_or_est&lt;/span&gt;)
    is_draft &lt;span class="Keyword"&gt;=&lt;/span&gt; inv_or_est.&lt;span class="Entity"&gt;status&lt;/span&gt; &lt;span class="Keyword"&gt;==&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;draft&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; is_draft
      inv_or_est.&lt;span class="Entity"&gt;status&lt;/span&gt;&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;sent&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      update_success &lt;span class="Keyword"&gt;=&lt;/span&gt; inv_or_est.&lt;span class="Entity"&gt;update&lt;/span&gt; &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; Fail if this is false&lt;/span&gt;
      &lt;span class="Keyword"&gt;raise&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;FreshBooks API has changed. Document could not be readied.&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;unless&lt;/span&gt; update_success
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
    logged_in_session_to_view_doc_url &lt;span class="Keyword"&gt;=&lt;/span&gt; inv_or_est.&lt;span class="Entity"&gt;links&lt;/span&gt;.&lt;span class="Entity"&gt;client_view&lt;/span&gt;
    cookiejar &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Tempfile&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;cookies&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="Comment"&gt;    &lt;span class="Comment"&gt;#&lt;/span&gt; Note this is particularly ugly because we require session cookies + redirect handling + bad SSL chain (thanks godaddy!). Bailed on Net::HTTP approach.&lt;/span&gt;
    html_doc &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;`&lt;/span&gt;wget &amp;quot;&lt;span class="String"&gt;&lt;span class="String"&gt;#{&lt;/span&gt;logged_in_session_to_view_doc_url&lt;span class="String"&gt;}&lt;/span&gt;&lt;/span&gt;&amp;quot;  --no-check-certificate --cookies=on --keep-session-cookies --save-cookies='&lt;span class="String"&gt;&lt;span class="String"&gt;#{&lt;/span&gt;cookiejar&lt;span class="String"&gt;&lt;span class="String"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;path&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;}&lt;/span&gt;&lt;/span&gt;'  -O -&lt;span class="String"&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class="Comment"&gt;    &lt;span class="Comment"&gt;#&lt;/span&gt; https://elc.freshbooks.com/getPDF.php&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; inv_or_est.&lt;span class="Entity"&gt;class&lt;/span&gt; &lt;span class="Keyword"&gt;==&lt;/span&gt; &lt;span class="Support"&gt;FreshBooks&lt;/span&gt;::&lt;span class="Entity"&gt;Estimate&lt;/span&gt;
      pd &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;estimate&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;else&lt;/span&gt;
      pd &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;invoice&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
    pdf_file &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Tempfile&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;pdf&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
    cmd &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;wget 'https://&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;&lt;span class="StringVariable"&gt;self&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;freshbooks_api_host&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;/getPDF.php' --post-data='&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;pd&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;id[]=&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;inv_or_est&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;number&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;' --cookies=on --keep-session-cookies --load-cookies='&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;cookiejar&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;path&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;'  --no-check-certificate -O '&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;pdf_file&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;path&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;'&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    pdf &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;`&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;#{&lt;/span&gt;cmd&lt;span class="String"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;`&lt;/span&gt;&lt;/span&gt;
    logger.&lt;span class="Entity"&gt;debug&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Get the actual PDF: &lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;cmd&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    cookiejar.&lt;span class="Entity"&gt;delete&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; is_draft
      inv_or_est.&lt;span class="Entity"&gt;status&lt;/span&gt;&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;draft&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      update_success &lt;span class="Keyword"&gt;=&lt;/span&gt; inv_or_est.&lt;span class="Entity"&gt;update&lt;/span&gt;;
      &lt;span class="Keyword"&gt;raise&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;FreshBooks API has changed. Document could not be readied.&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;unless&lt;/span&gt; update_success
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
    pdf_file
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;See more at: &lt;a href="http://github.com/elc/freshbooks.rb/tree/master"&gt; http://github.com/elc/freshbooks.rb/tree/master&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/oRNZyd7je7U" height="1" width="1"/&gt;</description>
      <author>Jonathan Siegel</author>
      <pubDate>Mon, 29 Jun 2009 02:06:39 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/oRNZyd7je7U/ruby-freshbooks-integration</link>
      <guid isPermaLink="false">http://elctech.com/tutorials/ruby-freshbooks-integration</guid>
    <feedburner:origLink>http://elctech.com/tutorials/ruby-freshbooks-integration</feedburner:origLink></item>
    <item>
      <title>Auto delta parent records in ThinkingSphinx</title>
      <description>&lt;div class="preface"&gt;
&lt;h2&gt;Auto updating sphinx delta on child record updates&lt;/h2&gt;
&lt;p&gt;Thinking Sphinx is quickly becoming the de-facto rails search plugin. In the past there have been a few other plugins that gained popularity and lost it almost as quickly by either being orphaned, outdated, etc. Thinking Sphinx has a clear path and a very involved/attentive maintainer.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Thinking Sphinx is quickly becoming the de-facto rails search plugin. In the past there have been a few other plugins that gained popularity and lost it almost as quickly by either being orphaned, outdated, etc. Thinking Sphinx has a clear path and a very involved/attentive maintainer.&lt;/p&gt;

&lt;p&gt;The way sphinx does it's "Live Updates" is through delta indexing. This allows indices to be added without rebuilding the master index. Thinking Sphinx handles new and updated records to be added to the delta through a couple of facilities, the one I will be focusing on is the delta boolean which is added to your index definition block like so:&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Variable"&gt;Class&lt;/span&gt; &lt;span class="Variable"&gt;UsedVehicle&lt;/span&gt; &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt; &lt;span class="Support"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="Entity"&gt;Base&lt;/span&gt;
  define_index &lt;span class="Keyword"&gt;do&lt;/span&gt;
    indexes [manufacturer, model], &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;as&lt;/span&gt; =&amp;gt; make_and_model
    indexes &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;trim_level&lt;/span&gt;
    indexes &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;year&lt;/span&gt;
    indexes &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;color&lt;/span&gt;
    indexes &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;condition&lt;/span&gt;
    indexes &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;price&lt;/span&gt;
    
&lt;span class="Comment"&gt;    &lt;span class="Comment"&gt;#&lt;/span&gt;index relations&lt;/span&gt;
    indexes option_package.&lt;span class="Entity"&gt;options&lt;/span&gt;, &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;as&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;options&lt;/span&gt;
    indexes accessories.&lt;span class="Entity"&gt;package&lt;/span&gt;, &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;as&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;accessory_package&lt;/span&gt;
    
&lt;span class="Comment"&gt;    &lt;span class="Comment"&gt;#&lt;/span&gt;this is to allow for delta index updating on record modification&lt;/span&gt;
    set_property &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;delta&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
  
  ...
  
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;In the example above we're indexing option_package.options and accessories.package which are ActiveRecord relations. Thinking Sphinx will update the parent UsedVehicle records in the delta when it sees them changed, through the 'delta' column on UsedVehicle, but what if you're updating the child records? Simple:&lt;/p&gt;

&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Variable"&gt;Class&lt;/span&gt; &lt;span class="Variable"&gt;OptionPackage&lt;/span&gt; &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt; &lt;span class="Support"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="Entity"&gt;Base&lt;/span&gt;
  after_update &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;set_parent_delta&lt;/span&gt;
  
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;set_parent_delta&lt;/span&gt;
    &lt;span class="Variable"&gt;self&lt;/span&gt;.&lt;span class="Entity"&gt;used_vehicle&lt;/span&gt;.&lt;span class="Entity"&gt;update_attributes&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;delta&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;)
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  ...

&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;Now you'd want to do the same to the Accessory class to get that updating also. And it's that simple.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/l-l1bQEkzA8" height="1" width="1"/&gt;</description>
      <author>Max, John</author>
      <pubDate>Fri, 26 Jun 2009 17:44:25 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/l-l1bQEkzA8/auto-delta-parent-records-in-thinkingsphinx</link>
      <guid isPermaLink="false">http://elctech.com/articles/auto-delta-parent-records-in-thinkingsphinx</guid>
    <feedburner:origLink>http://elctech.com/articles/auto-delta-parent-records-in-thinkingsphinx</feedburner:origLink></item>
    <item>
      <title>Scraping Images from Twitpics</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;Recently, I've been scraping Images and videos from Twitter and one site that has not been too easy to grab pics from is Twitpics. Here's a snippet of code that I've been using to grab the image from Twitpic with Hpricot:&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;net/http&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;hpricot&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;rip_twitpic&lt;/span&gt;(&lt;span class="Variable"&gt;url&lt;/span&gt;)
  &lt;span class="Keyword"&gt;begin&lt;/span&gt;
    code&lt;span class="Keyword"&gt;=&lt;/span&gt;url.&lt;span class="Entity"&gt;match&lt;/span&gt;(&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;[&lt;/span&gt;&lt;span class="StringRegexpSpecial"&gt;\w&lt;/span&gt;&lt;span class="StringRegexp"&gt;]&lt;/span&gt;&lt;/span&gt;+$&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;).&lt;span class="Entity"&gt;to_s&lt;/span&gt;
    &lt;span class="Keyword"&gt;unless&lt;/span&gt; code.&lt;span class="Entity"&gt;blank?&lt;/span&gt;
      uri&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="Variable"&gt;URI&lt;/span&gt;.&lt;span class="Entity"&gt;parse&lt;/span&gt;(url)
      resp&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="Support"&gt;Net&lt;/span&gt;::&lt;span class="Entity"&gt;HTTP&lt;/span&gt;.&lt;span class="Entity"&gt;get_response&lt;/span&gt;(uri)
      html&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="Variable"&gt;Hpricot&lt;/span&gt;(resp.&lt;span class="Entity"&gt;body&lt;/span&gt;)
      html.&lt;span class="Entity"&gt;at&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#photo-display&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)[&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;src&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;]
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;rescue&lt;/span&gt; &lt;span class="Variable"&gt;Exception&lt;/span&gt; =&amp;gt; e
    puts &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Error extracting twitpic: &lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;e&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    url
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;
&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note: Thanks to Stephen Boisvert for showing my typo. That's what I get for rushing something out and drinking too many cups of coffee.&lt;/em&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/qMrWeIYIJo8" height="1" width="1"/&gt;</description>
      <author>Alex Chee</author>
      <pubDate>Fri, 26 Jun 2009 00:15:09 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/qMrWeIYIJo8/scraping-images-from-twitpics</link>
      <guid isPermaLink="false">http://elctech.com/snippets/scraping-images-from-twitpics</guid>
    <feedburner:origLink>http://elctech.com/snippets/scraping-images-from-twitpics</feedburner:origLink></item>
    <item>
      <title>Coworking Visas: Offices Without Borders</title>
      <description>&lt;div class="preface"&gt;
&lt;img src="http://elccore.s3.amazonaws.com/15/785/you_talking.jpg" alt="You_talking" /&gt;
&lt;p&gt;Listen up, Señor T is talking to you. If you have ever tried to spend 8 hours working from a coffee shop, then I don't have to tell you that it's not all that it's cracked up to be. Yes, its a fun dynamic working environment, where people will make you coffee and tasty snacks. However, spotty internet connections, loud music, chatty patrons and lack of power outlets get old quick. But for a &lt;a href="http://www.elctech.com/articles/tips-and-tricks-from-a-self-proclaimed-cybernomad" target="_blank"&gt;cybernomad&lt;/a&gt; like me, plopping down a monitor on a desk just isn't an option.&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Shared Workspaces&lt;/h2&gt;
&lt;p&gt;In recent years, shared community orientated workspaces have been growing in numbers. Places like &lt;a href="http://www.soukllc.com/" target="_blank"&gt;Souk&lt;/a&gt;, which we jokingly refer to as the ELC Portland office, are great places to drop in and work. They have flexible memberships and sport all the accommodations of a regular office (except a boss). I am currently at &lt;a href="http://www.officenomads.com/" target="_blank"&gt;Office Nomads&lt;/a&gt; in Seattle and they even have a kegarator, a 48 inch TV and people doing Yoga.
&lt;img src="http://elccore.s3.amazonaws.com/15/780/officenomads.jpg" alt="Officenomads" /&gt;&lt;/p&gt;

&lt;h2&gt;Coworking Visas&lt;/h2&gt;
&lt;img src="http://elccore.s3.amazonaws.com/15/786/obama_sez.jpg" alt="Obama_sez" /&gt;
&lt;p&gt;But you still don't want to be stuck in the same city in the same shared office, because a shared office is still an office. Enter the &lt;a href="http://coworking.pbworks.com/CoworkingVisa" target="_blank"&gt;Coworking Visa&lt;/a&gt;, which is a network of shared workspaces like &lt;a href="http://www.soukllc.com/" target="_blank"&gt;Souk&lt;/a&gt; and &lt;a href="http://www.officenomads.com/" target="_blank"&gt;Office Nomads&lt;/a&gt; that allow you to float between them if you have a membership at one location. This isn't a small network either. They are in most major and some not so major US cities and 13 countries around the world, including Buenos Aires where I spent the last month. Anyways, its totally amazing and I encourage you all to pick up your computer and wander with it. Sorry the pictures are so bad, I broke my camera.
&lt;/p&gt;

&lt;img src="http://elccore.s3.amazonaws.com/15/779/egginhole.jpg" alt="Egginhole" /&gt;

&lt;p&gt;Yes that is egg-in-a-pancake-hole, I had it for breakfast.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/jAbQmEerkQM" height="1" width="1"/&gt;</description>
      <author>Nicholaus</author>
      <pubDate>Thu, 25 Jun 2009 17:19:34 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/jAbQmEerkQM/coworking-visas-offices-without-borders</link>
      <guid isPermaLink="false">http://elctech.com/articles/coworking-visas-offices-without-borders</guid>
    <feedburner:origLink>http://elctech.com/articles/coworking-visas-offices-without-borders</feedburner:origLink></item>
    <item>
      <title>ReCSS - AJAX friendly CSS testing</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;Back in the days when the web didn't yet have a version number, David from &lt;a href="http://dojotoolkit.org" target="_blank"&gt;dojotoolkit.org&lt;/a&gt; came up with a neat solution to reload your css without the need of reloading your page: &lt;a href="http://david.dojotoolkit.org/recss.html" target="_blank"&gt;ReCSS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's just a simple bookmarklet that walks through all linked stylesheets and reloads them. This omits page reloads in order to test your CSS changes, very helpful for AJAX heavy sites. Here is what the code looks like:&lt;/p&gt;

&lt;code language="javascript"&gt;&lt;pre class="sunburst"&gt;javascript: &lt;span class="Storage"&gt;void&lt;/span&gt;(&lt;span class="Storage"&gt;function&lt;/span&gt;() {
    &lt;span class="Storage"&gt;var&lt;/span&gt; i, a, s;
    a &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;document&lt;/span&gt;.&lt;span class="SupportFunction"&gt;getElementsByTagName&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;link&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;);
    &lt;span class="Keyword"&gt;for&lt;/span&gt; (i &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;; i &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt; a.&lt;span class="SupportConstant"&gt;length&lt;/span&gt;; i&lt;span class="Keyword"&gt;++&lt;/span&gt;) {
        s &lt;span class="Keyword"&gt;=&lt;/span&gt; a[i];
        &lt;span class="Keyword"&gt;if&lt;/span&gt; (s.&lt;span class="SupportConstant"&gt;rel&lt;/span&gt;.&lt;span class="SupportFunction"&gt;toLowerCase&lt;/span&gt;().&lt;span class="SupportFunction"&gt;indexOf&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;stylesheet&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="Keyword"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Keyword"&gt;&amp;amp;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;amp;&lt;/span&gt; s.&lt;span class="SupportConstant"&gt;href&lt;/span&gt;) {
            &lt;span class="Storage"&gt;var&lt;/span&gt; h &lt;span class="Keyword"&gt;=&lt;/span&gt; s.&lt;span class="SupportConstant"&gt;href&lt;/span&gt;.&lt;span class="SupportFunction"&gt;replace&lt;/span&gt;(&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;(&amp;amp;|%5C?)forceReload=&lt;span class="StringRegexpSpecial"&gt;\d&lt;/span&gt;+&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;);
            s.&lt;span class="SupportConstant"&gt;href&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; h &lt;span class="Keyword"&gt;+&lt;/span&gt; (h.&lt;span class="SupportFunction"&gt;indexOf&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;?&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="Keyword"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt; ? &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;&amp;amp;&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;: &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;?&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="Keyword"&gt;+&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;forceReload=&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;+&lt;/span&gt; (&lt;span class="Keyword"&gt;new&lt;/span&gt; &lt;span class="JEntityNameType"&gt;Date&lt;/span&gt;().&lt;span class="SupportFunction"&gt;valueOf&lt;/span&gt;())
        }
    }
})();
&lt;/pre&gt;&lt;/code&gt;


&lt;p&gt;This is one of the small things that makes my life easier, and I want to make sure that it does the same for you. Drag the following link to your Bookmarks toolbar and become a CSS rockstar: &lt;a href="javascript:void(function(){var%20i,a,s;a=document.getElementsByTagName('link');for(i=0;i&lt;a.length;i++){s=a[i];if(s.rel.toLowerCase().indexOf('stylesheet')&gt;=0&amp;&amp;s.href)%20{var%20h=s.href.replace(/(&amp;|%5C?)forceReload=\d+/,'');s.href=h+(h.indexOf('?')&gt;=0?'&amp;':'?')+'forceReload='+(new%20Date().valueOf())}}})();" target="_blank"&gt;ReCSS&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/nGsDk8BHSJw" height="1" width="1"/&gt;</description>
      <author>Gregor Martynus</author>
      <pubDate>Wed, 24 Jun 2009 23:02:35 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/nGsDk8BHSJw/recss---ajax-friendly-css-testing</link>
      <guid isPermaLink="false">http://elctech.com/snippets/recss---ajax-friendly-css-testing</guid>
    <feedburner:origLink>http://elctech.com/snippets/recss---ajax-friendly-css-testing</feedburner:origLink></item>
    <item>
      <title>jQuery ajax quick tip: $.ajax abort()</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;Dealing with ajax has become so easy and high-level that it is pretty easy to forget about the details. A nice habit to get into when dealing with an ajax-heavy frontend is to manage the event listeners and connections that a user can initiate.&lt;/p&gt;
&lt;p&gt;Something simple to remember is that you can't rely on your requests to complete FIFO because your requests are getting routed across multiple processes/machines that may or may not be under load.  Alot of users are rather click-happy (my mom still double-clicks links) which can lead to problems with content that was requested on the first click being loaded after the content from the most recent click.&lt;/p&gt;
&lt;p&gt;In the past I have always included sequence numbers as request ID's and then have the server include the request ID it is responding to in the JSON response. This gives the event handlers some context of the response it just received in relation to the most recent action the user has performed on the page.&lt;/p&gt;
&lt;p&gt;This works well, but sometimes &lt;strong&gt;you just want to throw out any response that is not in response to the most recent request.&lt;/strong&gt; This is where the &lt;strong&gt;abort()&lt;/strong&gt; method is useful.&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;var current_conn;

function &lt;span class="Entity"&gt;getSome&lt;/span&gt;() {
  &lt;span class="Keyword"&gt;if&lt;/span&gt;(current_request) {current_request.&lt;span class="Entity"&gt;abort&lt;/span&gt;();}
  current_request &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;$&lt;/span&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;get&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;/events&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;,
    { team : &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Ramrod&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }, 
    &lt;span class="Entity"&gt;function&lt;/span&gt;(resp) { &lt;span class="Entity"&gt;alert&lt;/span&gt;(resp); }
  );
}
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;If you need to, you could use the sequence number approach and create a response queue or other more complex solution. Here are a few neat ideas as well...&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.protofunc.com/scripts/jquery/ajaxManager/" target="_blank"&gt;http://www.protofunc.com/scripts/jquery/ajaxManager/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.mail-archive.com/discuss@jquery.com/msg03581.html" target="_blank"&gt;Simple queue idea&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/r2-_bxr1vAA" height="1" width="1"/&gt;</description>
      <author>Cary Dunn</author>
      <pubDate>Mon, 22 Jun 2009 18:47:43 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/r2-_bxr1vAA/jquery-ajax-quick-tip-ajax-abort</link>
      <guid isPermaLink="false">http://elctech.com/snippets/jquery-ajax-quick-tip-ajax-abort</guid>
    <feedburner:origLink>http://elctech.com/snippets/jquery-ajax-quick-tip-ajax-abort</feedburner:origLink></item>
    <item>
      <title>iPhone Tethering Without Jail-breaking Your iPhone</title>
      <description>&lt;div class="preface"&gt;
&lt;img src="http://elccore.s3.amazonaws.com/30/776/iPhone_3_0_tethering.jpg" alt="Iphone_3_0_tethering" /&gt;
&lt;p&gt;With the 3.0 update coming out for the iPhone, people have been talking about one of the new features called tethering.  Tethering is the process of using your mobile device's internet connection on your computer.  This allows you to have internet on your computer anywhere there is cell service.&lt;/p&gt;
&lt;p&gt;
   While phones like the Blackberry and Palm have had tethering for a few years, Apple has finally updated the new iPhone to include this feature.  The problem is the US carrier for the iPhone (AT&amp;T) will not support tethering for quite some time. And when they do decide to support it, they will charge an additional monthly fee.
&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;
    Up until now, the only way to get tethering on your iPhone was to hack it.  An app also came out a while ago that allowed you to do this, but it was quickly pulled from the app store.
&lt;/p&gt;

&lt;p&gt;
    So, the crew over at &lt;a href="http://www.9to5mac.com/9to5mac-tether-iPhone-hack" target="_blank"&gt;9to5mac&lt;/a&gt; have discovered a way to have tethering with any iPhone running the 3.0 update. They give you step by step instructions on how to do it. All it requires is iTunes 8.2, Their tethering app , and the 3.0 iPhone update.
&lt;/p&gt;

&lt;p&gt;
    While this solution is only temporary I'm sure as Apple/AT&amp;T is bound to catch on and fix the vulnerability, it is still very interesting.  So be sure to &lt;a href="http://www.9to5mac.com/9to5mac-tether-iPhone-hack" target="_blank"&gt;check it out&lt;/a&gt;.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/fjCaLg9gwI0" height="1" width="1"/&gt;</description>
      <author>Brandon Trebitowski</author>
      <pubDate>Mon, 15 Jun 2009 15:22:16 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/fjCaLg9gwI0/iphone-tethering-without-jail-breaking-your-iphone</link>
      <guid isPermaLink="false">http://elctech.com/articles/iphone-tethering-without-jail-breaking-your-iphone</guid>
    <feedburner:origLink>http://elctech.com/articles/iphone-tethering-without-jail-breaking-your-iphone</feedburner:origLink></item>
    <item>
      <title>Distributed Sphinx</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;While installing Sphinx for a largish application, I wasn't able to find many documented examples that touched on distributed deployments.  The examples I did find were either a bit complicated when it comes to setup and execution, or, they didn't necessarily meet my needs.  I "think" my needs are pretty simple:&lt;/p&gt;

&lt;p&gt;
&lt;hr /&gt;&lt;blockquote&gt;I need indexing to be fast, searching to be fast, result sets to be up-to-date, and, this painlessly deployed across a large and dynamic array of machines.&lt;/blockquote&gt;&lt;hr /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;That's reasonable, right?  Well, luckily for us, Sphinx actually handles all that, and more :)&lt;br /&gt;&lt;br /&gt;My only caveat is that the distributed deployment scenarios listed on the Sphinx site require quite a bit of setup and configuration.  It's really not &lt;em&gt;that&lt;/em&gt; much configuration, but, I want to take the path of least resistance for my particular scenario.  I'm going to list my requirements (which are most likely a common set), and some the options laid out for me.  If there are other solutions to this set of requirements in terms of deployment, I'd love to hear them, so comment away!&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;h3&gt;An Example Scenerio&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;We have about 50-60 application machines, a master database, some slaves, and a bunch of machines that play their own unique roles.  There are less than 50m records (with limited fields) that need indexed, so doing full nightly indexes won't be a big deal.&lt;/p&gt;

&lt;p&gt;Here are some of the approaches I've come across while surfing the interwave:&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;
&lt;h3&gt;Sharding&lt;/h3&gt;
&lt;/p&gt;
&lt;p&gt;
The official Sphinx documentation &lt;a href="http://www.sphinxsearch.com/docs/current.html#distributed" target="_blank"&gt;outlines a method&lt;/a&gt; for horizontally partitioning out indexes across a cluster of machines.  Patrick Galbraith has a great &lt;a href="http://capttofu.livejournal.com/13037.html" target="_blank"&gt;rundown of this approach&lt;/a&gt; as well.  The searchd processes are able to connect to configured remote agents, run the search, create a unique result set, and return the results.  This is a great approach, and it has been used to search through billions of records.  Impressive!
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Pros&lt;/b&gt;:  Great performance, master/slave configurable for high availability.&lt;br /&gt;
&lt;b&gt;Cons&lt;/b&gt;:  Hefty configuration.  No auto-discovery on nodes.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;
&lt;h3&gt;SCP&lt;/h3&gt;
&lt;/p&gt;
&lt;p&gt;
I've read quite a few cases of people enabling delta's across their cluster, doing a complete index on one machine, SCP'ing the index to all the machines in the their cluster, then HUP'ing all of the searchd's.  Phew... that was a sentence full!  This is definitely an iffy approach, but it works.  You'll run into inconsistent deltas across the cluster, and some hefty configuration, but if this isn't a problem for you, go for it :)
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Pros&lt;/b&gt;:  Straightforward.&lt;br /&gt;
&lt;b&gt;Cons&lt;/b&gt;:  Hefty configuration.  Out of synch deltas.  SCP.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;
&lt;h3&gt;NFS&lt;/h3&gt;
&lt;/p&gt;
&lt;p&gt;
Your machines can have NFS mounts that point to both the primary index, as well as a single delta index.  This doesn't require any special agent configuration, and your delta's will never be out of synch.  This is a win, but you may have significant write contention on your delta's, and, there will be some network overhead.
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Pros&lt;/b&gt;:  Light configuration.  Up-to-date delta's.&lt;br /&gt;
&lt;b&gt;Cons&lt;/b&gt;:  Delta contention on write heavy applications.  NFS.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;
For what it's worth, we're going to most likely roll with the NFS approach.  Our data set is minimal, the fields are not write heavy, and we don't want to worry about too much configuration (no agent configuration in sphinx.xml, just cycle up/down machines, and let NFS handle the rest).&lt;/p&gt;

&lt;p&gt;
I'm sure I'm probably missing some other snazzy setups that are out there in the wild, and I would love to add to this list.  Feel free to comment about other techniques that you may have seen, heard of, or have had experience with, and I'll add it to the list above!&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/eTdjQz-KDSg" height="1" width="1"/&gt;</description>
      <author>Dylan Stamat</author>
      <pubDate>Wed, 10 Jun 2009 01:41:22 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/eTdjQz-KDSg/distributed-sphinx</link>
      <guid isPermaLink="false">http://elctech.com/articles/distributed-sphinx</guid>
    <feedburner:origLink>http://elctech.com/articles/distributed-sphinx</feedburner:origLink></item>
    <item>
      <title>Upgrade GIT on OS/X</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;There's a new GIT version out with at least &lt;a href="http://jasonrudolph.com/blog/2009/05/27/git-up-10-reasons-to-upgrade-your-old-git-installation"&gt;10 reasons to upgrade&lt;/a&gt;. OS/X users of &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt; can get the GIT upgrade with:&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;$ sudo port selfupdate
$ sudo port upgrade git&lt;span class="Keyword"&gt;-&lt;/span&gt;core &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; not git!&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;If you try this on your MacBook Air like I did be prepared for massive sluggishness for up to 2 hours.&lt;/p&gt;

&lt;h2&gt;Don't Forget&lt;/h2&gt;
&lt;p&gt;To remove that annoying message you now get with git push:&lt;/p&gt;
&lt;/div&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;$ git push
warning: &lt;span class="Variable"&gt;You&lt;/span&gt; did &lt;span class="Keyword"&gt;not&lt;/span&gt; specify any refspecs to push, &lt;span class="Keyword"&gt;and&lt;/span&gt; the current remote
warning: has &lt;span class="Keyword"&gt;not&lt;/span&gt; configured any push refspecs. &lt;span class="Variable"&gt;The&lt;/span&gt; default action &lt;span class="Keyword"&gt;in&lt;/span&gt; this
warning: &lt;span class="Keyword"&gt;case&lt;/span&gt; is to push all matching refspecs, that is, all branches
warning: that exist both locally &lt;span class="Keyword"&gt;and&lt;/span&gt; remotely will be updated.  &lt;span class="Variable"&gt;This&lt;/span&gt; may
warning: &lt;span class="Keyword"&gt;not&lt;/span&gt; necessarily be what you want to happen.
warning: 
warning: &lt;span class="Variable"&gt;You&lt;/span&gt; can specify what action you want to take &lt;span class="Keyword"&gt;in&lt;/span&gt; this &lt;span class="Keyword"&gt;case&lt;/span&gt;, &lt;span class="Keyword"&gt;and&lt;/span&gt;
warning: avoid seeing this message again, by configuring &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;push.default&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt; to:
warning:   &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;nothing&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;  : &lt;span class="Variable"&gt;Do&lt;/span&gt; &lt;span class="Keyword"&gt;not&lt;/span&gt; push anything
warning:   &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;matching&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class="Variable"&gt;Push&lt;/span&gt; all matching branches (default)
warning:   &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;tracking&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class="Variable"&gt;Push&lt;/span&gt; the current branch to whatever it is tracking
warning:   &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;current&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;  : &lt;span class="Variable"&gt;Push&lt;/span&gt; the current branch
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;To keep the default setting and remove the warnings, just type:&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; Sets ~/.gitconfig which applies as default across all working dirs:&lt;/span&gt;
$ git config &lt;span class="Keyword"&gt;-&lt;/span&gt;&lt;span class="Keyword"&gt;-&lt;/span&gt;global push.&lt;span class="Entity"&gt;default&lt;/span&gt; matching
$ cat &lt;span class="Keyword"&gt;~&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;.gitconfig &lt;/span&gt;
&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;[&lt;/span&gt;push&lt;span class="StringRegexp"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="StringRegexp"&gt;	default = matching&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;Or if you'd like to set this on a project-by-project basis, make sure you are in a GIT working directory and:&lt;/p&gt;
 &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; Per project setting:&lt;/span&gt;
$ git config push.&lt;span class="Entity"&gt;default&lt;/span&gt; matching
&lt;/pre&gt;&lt;/code&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/w65EwkXmJ14" height="1" width="1"/&gt;</description>
      <author>Jonathan Siegel</author>
      <pubDate>Mon, 08 Jun 2009 09:54:19 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/w65EwkXmJ14/upgrade-git-on-os-x</link>
      <guid isPermaLink="false">http://elctech.com/tutorials/upgrade-git-on-os-x</guid>
    <feedburner:origLink>http://elctech.com/tutorials/upgrade-git-on-os-x</feedburner:origLink></item>
    <item>
      <title>Your STI Broke My Sphinx</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;If you're using Ultrasphinx in your rails application and you have models using ActiveRecord support for Single Table Inheritance, it might not work they way you;d like.  Actually it will break.&lt;/p&gt;
&lt;/div&gt;

&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; == Schema Information&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; Table name: fruits&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;  id              :integer(4)      not null, primary key&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;  type           :string(255)&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;  size           :integer(4)&lt;/span&gt;

&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="JEntityNameType"&gt;Apple&lt;span class="EntityInheritedClass"&gt; &lt;span class="EntityInheritedClass"&gt;&amp;lt;&lt;/span&gt; Fruit&lt;/span&gt;&lt;/span&gt;
  is_indexed &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;fields&lt;/span&gt; =&amp;gt; [&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;size&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;]
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;
If you try to run an Ultrasphinx call with the above definition, it will search an index that was built from the entire fruits table, returning ID's that will raise an ActiveRecord::RecordNotFound exception when put through Apple.find().  To fix it, use the conditions argument to change the sql query that sphinx uses to build its index.
&lt;/p&gt;

&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="JEntityNameType"&gt;Apple&lt;span class="EntityInheritedClass"&gt; &lt;span class="EntityInheritedClass"&gt;&amp;lt;&lt;/span&gt; Fruit&lt;/span&gt;&lt;/span&gt;
  is_indexed &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;fields&lt;/span&gt; =&amp;gt; [&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;size&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;], &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;conditions&lt;/span&gt; =&amp;gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;fruits.type = 'Apple'&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;

&lt;img src="http://elccore.s3.amazonaws.com/21/762/sti_sphinx.jpg" alt="Sti_sphinx" /&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/MebkQv7iOHg" height="1" width="1"/&gt;</description>
      <author>ceberz</author>
      <pubDate>Sat, 06 Jun 2009 04:19:55 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/MebkQv7iOHg/your-sti-broke-my-sphinx</link>
      <guid isPermaLink="false">http://elctech.com/snippets/your-sti-broke-my-sphinx</guid>
    <feedburner:origLink>http://elctech.com/snippets/your-sti-broke-my-sphinx</feedburner:origLink></item>
    <item>
      <title>Stubbing a method for all tests</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;
If you ever need to stub out a method for all tests in your test suite, for example a before filter in ApplicationController that goes takes a while to run, here's a neat trick.
&lt;/p&gt;
&lt;p&gt;
Stick the following in your spec_helper:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Support"&gt;Spec&lt;/span&gt;::&lt;span class="Entity"&gt;Runner&lt;/span&gt;.&lt;span class="Entity"&gt;configure&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;|&lt;span class="Variable"&gt;config&lt;/span&gt;|
  config.&lt;span class="Entity"&gt;before&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;each&lt;/span&gt;, &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;type&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;controller&lt;/span&gt;) &lt;span class="Keyword"&gt;do &lt;/span&gt;
    controller.&lt;span class="Entity"&gt;stub!&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;blog_feed&lt;/span&gt;).&lt;span class="Entity"&gt;and_return&lt;/span&gt;([])
  &lt;span class="Keyword"&gt;end&lt;/span&gt; 
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;
If you need to override the above for some specs, just put a similar block on top of the spec file. (Question: how can I remove the stub completely for just a few tests?) 
&lt;/p&gt;

&lt;p&gt;
It might not be the most elegant solution known to man, and it sure isn't very clean and could come back and bite you one day, but if you know what you're doing... ;)
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; Something like this might work for your unstubbing needs, but if the above is an ugly hack, this is a &lt;strong&gt;really&lt;/strong&gt; ugly hack and YMMV:
&lt;/p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="JEntityNameType"&gt;Object&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;unstub!&lt;/span&gt;(&lt;span class="Variable"&gt;method_name&lt;span class="Variable"&gt;,&lt;/span&gt; &lt;span class="Keyword"&gt;*&lt;/span&gt;args&lt;span class="Variable"&gt;,&lt;/span&gt; &lt;span class="Keyword"&gt;&amp;amp;&lt;/span&gt;blk&lt;/span&gt;)
    &lt;span class="Variable"&gt;self&lt;/span&gt;.&lt;span class="Entity"&gt;send&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;proxied_by_rspec__&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;method_name&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="Keyword"&gt;*&lt;/span&gt;args, &lt;span class="Keyword"&gt;&amp;amp;&lt;/span&gt;blk) &lt;span class="Keyword"&gt;if&lt;/span&gt; &lt;span class="Variable"&gt;self&lt;/span&gt;.&lt;span class="Entity"&gt;respond_to?&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;proxied_by_rspec__&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;method_name&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;

If you need to poke even deeper (and you really shouldn't), this might be useful to you:
&lt;/p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;rspec_guts &lt;span class="Keyword"&gt;=&lt;/span&gt; my_instance_of_something.&lt;span class="Entity"&gt;send&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;__mock_proxy&lt;/span&gt;) &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt; rspec works its magic on this object, which is a Spec::Mocks::Proxy&lt;/span&gt;
puts rspec_guts.&lt;span class="Entity"&gt;instance_variable_get&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;@proxied_methods&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).inspect
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;

&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/rcUWNpPGe2g" height="1" width="1"/&gt;</description>
      <author>David Palm</author>
      <pubDate>Thu, 04 Jun 2009 10:28:37 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/rcUWNpPGe2g/stubbing-a-method-for-all-tests</link>
      <guid isPermaLink="false">http://elctech.com/articles/stubbing-a-method-for-all-tests</guid>
    <feedburner:origLink>http://elctech.com/articles/stubbing-a-method-for-all-tests</feedburner:origLink></item>
    <item>
      <title>pdf2swf on Mac OS X and ASVM mismatch</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;
&lt;img src="http://elccore.s3.amazonaws.com/10/777/edge.jpg" alt="Edge" /&gt;The current version of swftools in macports is 0.8.1 and for many cases it's not good enough. In particular, for pdf2swf to generate swf files that are recognized as ASVM3 (i.e. Flash version 7+ I think, but do correct me if I'm wrong) you need swftools 0.9.0 or greater. Loading an external swf movie from within another is considerably more cumbersome if the virtual machine used in the two files versions differ.
&lt;/p&gt;
&lt;p&gt;
You know you ran into the above VM mismatch error if your Flash logs are telling you something like this:
&lt;/p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Variable"&gt;TypeError&lt;/span&gt;: &lt;span class="Variable"&gt;Error&lt;/span&gt; &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;1034: Type Coercion failed: cannot convert flash.display::AVM1Movie@1e3d9e01 to flash.display.MovieClip. &lt;/span&gt;
    at com.&lt;span class="Entity"&gt;elctech&lt;/span&gt;::&lt;span class="Entity"&gt;PdfViewer&lt;/span&gt;&lt;span class="Keyword"&gt;/&lt;/span&gt;&lt;span class="Entity"&gt;doneLoading&lt;/span&gt;()
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
The above error will show only if -- only if -- you have a &lt;a href="http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html" target="_blank"&gt;debugger enabled flashplayer&lt;/a&gt; and &lt;a href="http://www.websector.de/blog/2007/02/20/trace-outside-the-flash-ide-with-tail/" target="_blank"&gt;logging enabled&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  But as we said, the current macports version isn't recent enough, so what to do? One option is to install everything from source, which for a package such as swftools entails a &lt;strong&gt;lot&lt;/strong&gt; of dependencies. Another option is to install the current macports version anyway to get all the dependencies installed and then compile just the swftools package from source (http://www.swftools.org/download.html). Not ideal perhaps, but IMHO better.
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
If you get complaints about missing libraries towards the end of the ./configure phase, like this:
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt;
  &lt;span class="Keyword"&gt;*&lt;/span&gt; &lt;span class="Variable"&gt;The&lt;/span&gt; following headers&lt;span class="Keyword"&gt;/&lt;/span&gt;libraries are missing:  jpeglib ungif jpeglib.&lt;span class="Entity"&gt;h&lt;/span&gt; gif_lib.&lt;span class="Entity"&gt;h&lt;/span&gt;
  &lt;span class="Keyword"&gt;*&lt;/span&gt; &lt;span class="Variable"&gt;Disabling&lt;/span&gt; pdf2swf tool...
  &lt;span class="Keyword"&gt;*&lt;/span&gt; &lt;span class="Variable"&gt;Disabling&lt;/span&gt; jpeg2swf tool...
  &lt;span class="Keyword"&gt;*&lt;/span&gt; &lt;span class="Variable"&gt;Disabling&lt;/span&gt; gif2swf tool...
  &lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
... try this:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Variable"&gt;LDFLAGS&lt;/span&gt;&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;-L/opt/local/lib&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Variable"&gt;CPPFLAGS&lt;/span&gt;&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;-I/opt/local/include -I/opt/local/include/lame&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; .&lt;span class="Keyword"&gt;/&lt;/span&gt;configure
  
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;
...to make sure your macports installed libs/headers are picked up.
&lt;/p&gt;
&lt;p&gt;
If/when make fail with something like:
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  ld: &lt;span class="Keyword"&gt;in&lt;/span&gt; ..&lt;span class="Keyword"&gt;/&lt;/span&gt;libgfxswf.&lt;span class="Entity"&gt;a&lt;/span&gt;, archive has no table of contents 
  collect2: ld returned &lt;span class="Constant"&gt;1&lt;/span&gt; exit status 
  make[&lt;span class="Constant"&gt;1&lt;/span&gt;]: &lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt; [pdf2swf] &lt;span class="Variable"&gt;Error&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt; 
  make: &lt;span class="Keyword"&gt;**&lt;/span&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt; [all] &lt;span class="Variable"&gt;Error&lt;/span&gt; &lt;span class="Constant"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
  ...run:
&lt;/p&gt;
&lt;p&gt;
  &lt;/p&gt;&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;    ranlib lib&lt;span class="Keyword"&gt;/&lt;/span&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt;.&lt;span class="Entity"&gt;a&lt;/span&gt;
    make
  
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;  
&lt;/p&gt;
&lt;p&gt;
  ...and the compile will continue. 'sudo make install' to finish.
&lt;/p&gt;

&lt;p&gt;
I'd love to write a more thorough explanation for the ranlib magic here, but I honestly don't have a clue. It's key not to run 'make clean' or './configure' again here, just the ranlib stuff and it will pick up where it got confused. Somehow. If anyone knows of a good resource for ranlib I'd love to dig further into this.
&lt;/p&gt;
&lt;img src="http://elccore.s3.amazonaws.com/10/778/hapiness.jpg" alt="Hapiness" /&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/6RT3SWNjAWc" height="1" width="1"/&gt;</description>
      <author>David Palm</author>
      <pubDate>Tue, 02 Jun 2009 19:50:18 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/6RT3SWNjAWc/pdf2swf-on-mac-os-x-and-asvm-mismatch</link>
      <guid isPermaLink="false">http://elctech.com/articles/pdf2swf-on-mac-os-x-and-asvm-mismatch</guid>
    <feedburner:origLink>http://elctech.com/articles/pdf2swf-on-mac-os-x-and-asvm-mismatch</feedburner:origLink></item>
    <item>
      <title>Deep Linking Pagination with jQuery Address</title>
      <description>&lt;div class="preface"&gt;
  &lt;p&gt;With most sites today so heavily reliant on loads of asyncronous requests with javascript,
    json/p, flash, etc. It can be quite frustrating when trying to navigate a JS image gallery or RSS reader
    while also making sure never to accidently hit back/forward/refresh so that you do not lose your place in browsing. 
    Want to send a link to the specific photo you are browsing in a JS gallery? Good luck getting your friends to click 
    the link and then hit "Next" 32 times to see the specific photo.&lt;/p&gt;
    
  &lt;p&gt;Facebook does a great job at keeping all of their heavy javascript pages (such as the photo gallery) deep-linked so this is not 
    an issue.&lt;/p&gt;
    
  &lt;p&gt;In the past, the most popular library for deep-linking was &lt;a href="http://www.asual.com/swfaddress/" target="_blank"&gt;swfAddress&lt;/a&gt; and was primarily used for Flash. 
    swfAddress now supports AJAX though the same team has also released a lightweight version for jQuery called &lt;a href="http://www.asual.com/jquery/address/" target="_blank"&gt;jQuery Address&lt;/a&gt;.&lt;/p&gt;
    
  &lt;p&gt;To demostrate deep-linking with jQuery Address I put together a quick demo of deep-linked pagination of a Flickr photo gallery as an example.  You should be able to use your back/forward/refresh/bookmark functions just fine.&lt;/p&gt;
  
  &lt;h2&gt;&lt;a href="http://elccore.s3.amazonaws.com/productdemos/deeplink/index.html" target="_blank"&gt;View Demo&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;

&lt;h2&gt;Source&lt;/h2&gt;
&lt;code language="javascript"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Keyword"&gt;!&lt;/span&gt;DOCTYPE html PUBLIC &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;-//W3C//DTD XHTML 1.0 Strict//EN&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;html xmlns&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;http://www.w3.org/1999/xhtml&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;head&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;title&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;jQuery Address &lt;span class="Keyword"&gt;+&lt;/span&gt; Flickr Pagination Demo&lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/title&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;meta content&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;text/html; charset=utf-8&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; http&lt;span class="Keyword"&gt;-&lt;/span&gt;equiv&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;content-type&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; /&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;script type&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;text/javascript&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/script&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;script type&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;text/javascript&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;jquery.address-1.0.min.js&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/script&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;script type&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;text/javascript&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;jquery.flickr-1.0-min.js&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/script&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;style type&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;text/css&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
        div#flickr_photos ul { overflow: hidden; list&lt;span class="Keyword"&gt;-&lt;/span&gt;style&lt;span class="Keyword"&gt;-&lt;/span&gt;type: none; margin: 0px; padding: 0px; }
        div#flickr_photos ul li { &lt;span class="Storage"&gt;float&lt;/span&gt;: left; }
        div#flickr_pagination a, div#flickr_pagination span { margin&lt;span class="Keyword"&gt;-&lt;/span&gt;right: 10px; }
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/style&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;script type&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;text/javascript&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;/*&lt;/span&gt;&amp;lt;![CDATA[&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;/span&gt;
        &lt;span class="Storage"&gt;var&lt;/span&gt; current_page &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;;

        &lt;span class="Storage"&gt;function&lt;/span&gt; &lt;span class="Entity"&gt;refreshPagination&lt;/span&gt;(&lt;span class="Variable"&gt;ele&lt;/span&gt;) {
          &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_loader&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).&lt;span class="SupportFunction"&gt;remove&lt;/span&gt;();

          &lt;span class="Storage"&gt;var&lt;/span&gt; current_page &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="SupportFunction"&gt;parseInt&lt;/span&gt;(&lt;span class="Keyword"&gt;$&lt;/span&gt;(ele).&lt;span class="SupportFunction"&gt;find&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;input:eq(0)&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).val());
          &lt;span class="Storage"&gt;var&lt;/span&gt; total_pages &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="SupportFunction"&gt;parseInt&lt;/span&gt;(&lt;span class="Keyword"&gt;$&lt;/span&gt;(ele).&lt;span class="SupportFunction"&gt;find&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;input:eq(1)&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).val());

          &lt;span class="Keyword"&gt;if&lt;/span&gt;(current_page &lt;span class="Keyword"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;) {
            &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&amp;lt;span&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Previous&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).appendTo(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
            &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&amp;lt;a&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).attr(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;href&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Next&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).bind(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;click&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, nextPage).appendTo(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
          } &lt;span class="Keyword"&gt;else&lt;/span&gt; &lt;span class="Keyword"&gt;if&lt;/span&gt; (current_page &lt;span class="Keyword"&gt;&amp;gt;=&lt;/span&gt; total_pages) {
            &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&amp;lt;a&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).attr(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;href&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Previous&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).bind(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;click&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, previousPage).appendTo(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
            &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&amp;lt;span&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Next&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).appendTo(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
          } &lt;span class="Keyword"&gt;else&lt;/span&gt; {
            &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&amp;lt;a&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).attr(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;href&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Previous&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).bind(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;click&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, previousPage).appendTo(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
            &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&amp;lt;a&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).attr(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;href&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Next&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).bind(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;click&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, nextPage).appendTo(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); 
          }
        }

        &lt;span class="Storage"&gt;function&lt;/span&gt; &lt;span class="Entity"&gt;previousPage&lt;/span&gt;() {
          &lt;span class="Keyword"&gt;$&lt;/span&gt;.address.&lt;span class="SupportConstant"&gt;value&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;?page=&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;+&lt;/span&gt;(current_page&lt;span class="Keyword"&gt;-&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;));
          &lt;span class="Keyword"&gt;return&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;;
        }

        &lt;span class="Storage"&gt;function&lt;/span&gt; &lt;span class="Entity"&gt;nextPage&lt;/span&gt;() {
          &lt;span class="Keyword"&gt;$&lt;/span&gt;.address.&lt;span class="SupportConstant"&gt;value&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;?page=&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;+&lt;/span&gt;(current_page&lt;span class="Keyword"&gt;+&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;));
          &lt;span class="Keyword"&gt;return&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;;
        }

        &lt;span class="Storage"&gt;function&lt;/span&gt; &lt;span class="Entity"&gt;getPhotos&lt;/span&gt;(&lt;span class="Variable"&gt;page&lt;/span&gt;) {
          &lt;span class="Keyword"&gt;$&lt;/span&gt;.address.&lt;span class="SupportConstant"&gt;title&lt;/span&gt;(&lt;span class="Keyword"&gt;$&lt;/span&gt;.address.&lt;span class="SupportConstant"&gt;title&lt;/span&gt;().&lt;span class="SupportFunction"&gt;split&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt; | &lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)[&lt;span class="Constant"&gt;0&lt;/span&gt;] &lt;span class="Keyword"&gt;+&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt; | page &lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;+&lt;/span&gt;page);

          &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_photos&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&amp;lt;img/&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).attr(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;src&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;spinner.gif&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).attr(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;id&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;flickr_loader&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
          &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);

          &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;#flickr_photos&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).flickr({
      			api_key: &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;f28804be7a09c5845676349c7e47d636&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,     
      			per_page: &lt;span class="Constant"&gt;5&lt;/span&gt;,
      			page: page,
      			type: &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;photoset&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      			photoset_id: &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;72157600037079977&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      			callback: refreshPagination
      		});
        }

        &lt;span class="Storage"&gt;function&lt;/span&gt; &lt;span class="Entity"&gt;addressChangeHandler&lt;/span&gt;(&lt;span class="Variable"&gt;evt&lt;/span&gt;) {
          current_page &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Keyword"&gt;$&lt;/span&gt;.address.parameter(&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;page&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
          &lt;span class="Keyword"&gt;if&lt;/span&gt;(current_page) {
            current_page &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="SupportFunction"&gt;parseInt&lt;/span&gt;(current_page);
          } &lt;span class="Keyword"&gt;else&lt;/span&gt; {
            current_page &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;;
          }

          getPhotos(current_page);
        }

        &lt;span class="Keyword"&gt;$&lt;/span&gt;(&lt;span class="Support"&gt;document&lt;/span&gt;).ready(&lt;span class="Storage"&gt;function&lt;/span&gt;(){
          &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;//&lt;/span&gt; Setup jQuery Address Listener&lt;/span&gt;
          &lt;span class="Keyword"&gt;$&lt;/span&gt;.address.change(addressChangeHandler);
        });
        &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;/*&lt;/span&gt;]]&amp;gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;/span&gt;
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/script&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/head&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;body&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;div id&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;flickr_photos&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/div&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;div id&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;flickr_pagination&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/div&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/body&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;&amp;lt;&lt;/span&gt;/html&lt;span class="Keyword"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/JWS79sPYrlU" height="1" width="1"/&gt;</description>
      <author>Cary Dunn</author>
      <pubDate>Tue, 02 Jun 2009 19:17:36 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/JWS79sPYrlU/deep-linking-pagination-with-jquery-address</link>
      <guid isPermaLink="false">http://elctech.com/tutorials/deep-linking-pagination-with-jquery-address</guid>
    <feedburner:origLink>http://elctech.com/tutorials/deep-linking-pagination-with-jquery-address</feedburner:origLink></item>
    <item>
      <title>The case of mysterious user interface</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;Until web coders and designers become one and the same, how does one deal with designing a website that is user interface heavy?  Does it mean that all designers should learn to code?  Or should all coders learn how to design?  &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
I often come across site specification that came with both feature description and mock designs attached to it.  In the olden days when everything is static, this was perfect.  Each mock is treated as a definite state and you can easily see the flow operational flow from one mock to the next.  For example, if you have a form submission page, then you have a submission result page.  As a user, you are trained to think that everything works like a two-step cha-cha: submit, result, submit , result, Ba da bing, ba da boom.
&lt;/p&gt;
&lt;p&gt;
This web behavior, however, is changing.  As functionally heavy sties such as social network sites start to emerge, people start to demand instantaneous feedback.  Out goes the dedicated landing page for submission result, and in comes the thank you popup powered by Ajax.  Although the underpinning of the web infrastructure hasn't changed, the change of behavior provides a sense of orientation and expedited response that makes users feel more empowered.
&lt;/p&gt;
&lt;p&gt;
Now, what does it all mean for the designers?  No longer is it enough for a designer to just make things look pretty.  These days things need to be both pretty and functional.  Without actually coding to demonstrate the user interaction, designers will be forced to spend incredible amount of time documenting and create a mock for all possible interactions.   Worse than being inefficient in using the designers' time is that coders struggle with the case mysterious user interface and make up their own interaction.
&lt;/p&gt;
&lt;p&gt;
As web design is starting to lean towards the user interface design, I have no doubt that the line that separates a web graphic designer and a web coder will be blurred even more.   Until then, I think the best compromise is for people to rely heavily on the communication between the designers and the coders.  Some may compare the separation between coders and designers like the model and view, and argue that this separation is necessary.  I certainly agree that it's necessary when it comes to software engineering.  I would even agree with that on the theoretic level.  But when it comes to human engineering, I would still say that talking is the best user interface there is.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/HzXdF4nmHSw" height="1" width="1"/&gt;</description>
      <author>Rick</author>
      <pubDate>Mon, 01 Jun 2009 19:06:22 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/HzXdF4nmHSw/the-case-of-mysterious-user-interface</link>
      <guid isPermaLink="false">http://elctech.com/articles/the-case-of-mysterious-user-interface</guid>
    <feedburner:origLink>http://elctech.com/articles/the-case-of-mysterious-user-interface</feedburner:origLink></item>
    <item>
      <title>RightSignature Featured on TechCrunch</title>
      <description>&lt;div class="preface"&gt;

&lt;h2 style="text-align:center"&gt;&lt;a href="http://rightsignature.com"&gt;Check out RightSignature&lt;/a&gt;&lt;/h2&gt;

&lt;a href="http://www.techcrunch.com/2009/05/29/make-your-mark-rightsignature-lets-you-sign-documents-online-or-on-your-iphone/"&gt;
&lt;img src="http://elccore.s3.amazonaws.com/3/753/rs_on_techcrunch-small.gif" alt="Rs_on_techcrunch-small" /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/XtHcLm6iCWI" height="1" width="1"/&gt;</description>
      <author>Daniel LaBare</author>
      <pubDate>Sat, 30 May 2009 03:25:51 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/XtHcLm6iCWI/rightsignature-featured-on-techcrunch</link>
      <guid isPermaLink="false">http://elctech.com/articles/rightsignature-featured-on-techcrunch</guid>
    <feedburner:origLink>http://elctech.com/articles/rightsignature-featured-on-techcrunch</feedburner:origLink></item>
    <item>
      <title>Merging Hash and HashWithIndifferentAccess</title>
      <description>&lt;div class="preface"&gt;

   &lt;p&gt;Ran into a gotcha the other day I thought I'd share. It came about in some code that was trying to give some default values in a hash, then merge in some params before creating an object. It looked something like this:&lt;/p&gt;

   &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;   &lt;span class="Support"&gt;Thing&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;({&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;is_cool&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;}.&lt;span class="Entity"&gt;merge&lt;/span&gt;(params[&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;thing&lt;/span&gt;])
   
&lt;/pre&gt;&lt;/code&gt;

   &lt;p&gt;The gotcha here is that params is a HashWithIndifferentAccess, but {:is_cool =&gt; true} is not. Merging these two will actually drop the return value to just Hash. Observe.&lt;/p&gt;

   &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;   &lt;span class="Keyword"&gt;&amp;gt;&amp;gt;&lt;/span&gt; params &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;HashWithIndifferentAccess&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;thing&lt;/span&gt; =&amp;gt; {&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;is_cool&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;false&lt;/span&gt;, &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;name&lt;/span&gt; =&amp;gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Cool Thing&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;})
   =&amp;gt; {&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;thing&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;{&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;name&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Cool Thing&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;is_cool&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;&lt;span class="Constant"&gt;false&lt;/span&gt;}}
   &lt;span class="Keyword"&gt;&amp;gt;&amp;gt;&lt;/span&gt; params.&lt;span class="Entity"&gt;class&lt;/span&gt;
   =&amp;gt; &lt;span class="Variable"&gt;HashWithIndifferentAccess&lt;/span&gt;
   &lt;span class="Keyword"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ({&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;is_class&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;}.&lt;span class="Entity"&gt;merge&lt;/span&gt;(params[&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;thing&lt;/span&gt;])).&lt;span class="Entity"&gt;class&lt;/span&gt;
   =&amp;gt; &lt;span class="Variable"&gt;Hash&lt;/span&gt;
   
&lt;/pre&gt;&lt;/code&gt;

   &lt;p&gt;When you look at what is created when merging the two, you notice that there are actually two separate keys of the same name, one a symbol, one a string.&lt;/p&gt;

   &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;    &lt;span class="Keyword"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;is_cool&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;}.&lt;span class="Entity"&gt;merge&lt;/span&gt;(params[&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;thing&lt;/span&gt;])
    =&amp;gt; {&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;name&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Cool Thing&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;is_cool&lt;/span&gt;=&amp;gt;&lt;span class="Constant"&gt;true&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;is_cool&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;&lt;span class="Constant"&gt;false&lt;/span&gt;}
   
&lt;/pre&gt;&lt;/code&gt;

   &lt;p&gt;And then when you pass this hash to your ActiveRecord model, you can see that it favors the symbol.&lt;/p&gt;

   &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;   &lt;span class="Keyword"&gt;&amp;gt;&amp;gt;&lt;/span&gt; thing &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Thing&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;({&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;is_cool&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;}.&lt;span class="Entity"&gt;merge&lt;/span&gt;(params[&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;thing&lt;/span&gt;]))
   =&amp;gt; &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;&amp;lt;Thing id: nil, name: &amp;quot;Cool Thing&amp;quot;, is_cool: true, created_at: nil, updated_at: nil&amp;gt;&lt;/span&gt;
   
&lt;/pre&gt;&lt;/code&gt;
   
   &lt;p&gt;The solution is to either use a string as your key:&lt;/p&gt;
   
   &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;   &lt;span class="Keyword"&gt;&amp;gt;&amp;gt;&lt;/span&gt; thing &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Thing&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;({&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;is_cool&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;}.&lt;span class="Entity"&gt;merge&lt;/span&gt;(params[&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;thing&lt;/span&gt;]))
   =&amp;gt; &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;&amp;lt;Thing id: nil, name: &amp;quot;Cool Thing&amp;quot;, is_cool: false, created_at: nil, updated_at: nil&amp;gt;&lt;/span&gt;
   
&lt;/pre&gt;&lt;/code&gt;

   &lt;p&gt;Or make the initial hash a HashWithIndifferentAccess:&lt;/p&gt;
   
   &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;   &lt;span class="Keyword"&gt;&amp;gt;&amp;gt;&lt;/span&gt; thing &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Thing&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;(&lt;span class="Support"&gt;HashWithIndifferentAccess&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;is_cool&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;).&lt;span class="Entity"&gt;merge&lt;/span&gt;(params[&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;thing&lt;/span&gt;]))
   =&amp;gt; &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;&amp;lt;Thing id: nil, name: &amp;quot;Cool Thing&amp;quot;, is_cool: false, created_at: nil, updated_at: nil&amp;gt;&lt;/span&gt;
   
&lt;/pre&gt;&lt;/code&gt;
   
   &lt;p&gt;So yea, keep an eye out for this gremlin.&lt;/p&gt;

&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/lYTOHyogDr0" height="1" width="1"/&gt;</description>
      <author>Daniel LaBare</author>
      <pubDate>Thu, 28 May 2009 22:23:37 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/lYTOHyogDr0/merging-hash-and-hashwithindifferentaccess</link>
      <guid isPermaLink="false">http://elctech.com/snippets/merging-hash-and-hashwithindifferentaccess</guid>
    <feedburner:origLink>http://elctech.com/snippets/merging-hash-and-hashwithindifferentaccess</feedburner:origLink></item>
    <item>
      <title>Agile sighting in LAX</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;Well...sort of an agile sighting...I mean, not really but sort of ;-)&lt;/p&gt;
&lt;img src="http://elccore.s3.amazonaws.com/21/750/scrum_shirt.jpg" alt="Scrum_shirt" /&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/ebwxQ6zhLpk" height="1" width="1"/&gt;</description>
      <author>ceberz</author>
      <pubDate>Thu, 28 May 2009 18:23:32 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/ebwxQ6zhLpk/agile-sighting-in-lax</link>
      <guid isPermaLink="false">http://elctech.com/articles/agile-sighting-in-lax</guid>
    <feedburner:origLink>http://elctech.com/articles/agile-sighting-in-lax</feedburner:origLink></item>
    <item>
      <title>Copy S3 assets with right_aws</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;Lately, I've been using right_aws to interact with S3. One thing that I found helpful was copying assets between buckets and keeping the same permissions on them. However, it's not as simple as just copying the assets over. You need to get the Access Control Policy from the source and put it in the copied asset.&lt;/p&gt;

&lt;p&gt;
Here's a snippet of code that does the magic.
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;rubygems&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt; 
&lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;right_aws&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt; 

s3&lt;span class="Keyword"&gt;=&lt;/span&gt;&lt;span class="Support"&gt;RightAws&lt;/span&gt;::&lt;span class="Entity"&gt;S3Interface&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;(&lt;span class="Variable"&gt;S3_KEY&lt;/span&gt;, &lt;span class="Variable"&gt;S3_SECRET&lt;/span&gt;)
s3.&lt;span class="Entity"&gt;copy&lt;/span&gt;(&lt;span class="Variable"&gt;SOURCE_BUCKET&lt;/span&gt;, &lt;span class="Variable"&gt;SOURCE_PATH&lt;/span&gt;, &lt;span class="Variable"&gt;DESTINATION_BUCKET&lt;/span&gt;, &lt;span class="Variable"&gt;DESTINATION_PATH&lt;/span&gt;, &lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;copy&lt;/span&gt;, {&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Cache-Control&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;max-age=315360000&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Expires&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;315360000&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;})
acl_prop&lt;span class="Keyword"&gt;=&lt;/span&gt;s3.&lt;span class="Entity"&gt;get_acl&lt;/span&gt;(&lt;span class="Variable"&gt;SOURCE_BUCKET&lt;/span&gt;, &lt;span class="Variable"&gt;SOURCE_PATH&lt;/span&gt;)
s3.&lt;span class="Entity"&gt;put_acl&lt;/span&gt;(&lt;span class="Variable"&gt;DESTINATION_BUCKET&lt;/span&gt;, &lt;span class="Variable"&gt;DESTINATION&lt;/span&gt;, acl_prop[&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;object&lt;/span&gt;])
&lt;/pre&gt;&lt;/code&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/P3K7TESXLqU" height="1" width="1"/&gt;</description>
      <author>Alex Chee</author>
      <pubDate>Thu, 28 May 2009 17:33:15 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/P3K7TESXLqU/copy-s3-assets-with-right_aws</link>
      <guid isPermaLink="false">http://elctech.com/snippets/copy-s3-assets-with-right_aws</guid>
    <feedburner:origLink>http://elctech.com/snippets/copy-s3-assets-with-right_aws</feedburner:origLink></item>
    <item>
      <title>Ruby 1.9 isn't always faster: rake tab-completion revisited</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;
  Rake is awesome in many ways and we're all using it for a plethora of tasks. It's easy to use, fast to code and reliable.
&lt;/p&gt;
&lt;p&gt;
  A while back I blogged about tab completion for rake tasks and the other day I set out to speed it up, as the project I was working on had a huge amount of tasks and retrieving the list of tasks took a loooong while.
&lt;/p&gt;
&lt;p&gt;
  As it turns out, speeding up the task enumeration is not a trivial task. My first thought was to ParseTree but it was horrendously slow and quite complex. Then I thought I'd use a fast language, such as OCaml or perhaps even C to scan the files and become known worldwide for my wicked coding skillz.
&lt;/p&gt;
  
&lt;p&gt;
  Didn't happen. As I'm sure you've already figured out, the rake library allows you to define raketasks in many different ways and people out there all seem to have different opinions on how to code up their tasks. Several important libraries define the rake tasks dynamically, ruling out any pattern matching approaches.
&lt;/p&gt;
  
&lt;p&gt;
  In other words I failed. But I also learned a lot and thanks to ruby-talk I also found a trick to make things spiffier: Ruby 1.9 isn't always faster, Rake::Application is a singleton and String#hash isn't what it used to be.
&lt;/p&gt;
  
&lt;p&gt;
  Read on for details.
&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Rake tab completion&lt;/h2&gt;
&lt;p&gt;
  The first step to setup rake tab completion is to tell bash to invoke your script when 'rake' is the command. Drop this in your ~/.bashrc:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  complete &lt;span class="Keyword"&gt;-&lt;/span&gt;&lt;span class="Variable"&gt;C&lt;/span&gt; &lt;span class="Keyword"&gt;~&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;bin&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;rake_completion.&lt;span class="Entity"&gt;rb&lt;/span&gt; &lt;span class="Keyword"&gt;-&lt;/span&gt;o default rake
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;
  The next step is the ruby executable script that actually looks up the rake tasks. The script:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Comment"&gt;  &lt;span class="Comment"&gt;#&lt;/span&gt;!/usr/bin/env ruby&lt;/span&gt;
 
&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;rake_silent_tasks&lt;/span&gt;
  dotcache &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;&lt;span class="Support"&gt;File&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;join&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;(&lt;/span&gt;&lt;span class="Support"&gt;File&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;expand_path&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;~&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;)&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;,&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;.raketabs-&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;&lt;span class="Support"&gt;Dir&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;pwd&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;hash&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;)&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;if&lt;/span&gt; &lt;span class="Support"&gt;File&lt;/span&gt;.&lt;span class="Entity"&gt;exists?&lt;/span&gt;(dotcache)
    &lt;span class="Support"&gt;Marshal&lt;/span&gt;.&lt;span class="Entity"&gt;load&lt;/span&gt;(&lt;span class="Support"&gt;File&lt;/span&gt;.&lt;span class="Entity"&gt;read&lt;/span&gt;(dotcache))
  &lt;span class="Keyword"&gt;else&lt;/span&gt;
    &lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;rubygems&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;rake&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
    load &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Rakefile&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
    tasks &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Rake&lt;/span&gt;.&lt;span class="Entity"&gt;application&lt;/span&gt;.&lt;span class="Entity"&gt;tasks&lt;/span&gt;.&lt;span class="Entity"&gt;map&lt;/span&gt;(&lt;span class="Keyword"&gt;&amp;amp;&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;name&lt;/span&gt;)
    &lt;span class="Support"&gt;File&lt;/span&gt;.&lt;span class="Entity"&gt;open&lt;/span&gt;(dotcache, &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;w&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;) { |&lt;span class="Variable"&gt;f&lt;/span&gt;| f.&lt;span class="Entity"&gt;puts&lt;/span&gt; &lt;span class="Support"&gt;Marshal&lt;/span&gt;.&lt;span class="Entity"&gt;dump&lt;/span&gt;(tasks) }
    tasks &lt;span class="Keyword"&gt;||&lt;/span&gt; []
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
 
exit &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Keyword"&gt;unless&lt;/span&gt; &lt;span class="Support"&gt;File&lt;/span&gt;.&lt;span class="Entity"&gt;file?&lt;/span&gt;(&lt;span class="Support"&gt;File&lt;/span&gt;.&lt;span class="Entity"&gt;join&lt;/span&gt;(&lt;span class="Support"&gt;Dir&lt;/span&gt;.&lt;span class="Entity"&gt;pwd&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Rakefile&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;))
exit &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Keyword"&gt;unless&lt;/span&gt; matches &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Variable"&gt;ENV&lt;/span&gt;[&lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;COMP_LINE&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;].&lt;span class="Entity"&gt;match&lt;/span&gt;(&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;^rake&lt;span class="StringRegexpSpecial"&gt;\s&lt;/span&gt;+&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;(&lt;/span&gt;.*&lt;span class="StringRegexp"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;)
 
after_match &lt;span class="Keyword"&gt;=&lt;/span&gt; matches[&lt;span class="Constant"&gt;1&lt;/span&gt;]
task_match &lt;span class="Keyword"&gt;=&lt;/span&gt; after_match.&lt;span class="Entity"&gt;strip&lt;/span&gt;.&lt;span class="Entity"&gt;empty?&lt;/span&gt; &lt;span class="Keyword"&gt;?&lt;/span&gt; &lt;span class="Constant"&gt;nil&lt;/span&gt; : after_match.&lt;span class="Entity"&gt;strip&lt;/span&gt;.&lt;span class="Entity"&gt;split&lt;/span&gt;.&lt;span class="Entity"&gt;last&lt;/span&gt;
 
&lt;span class="Keyword"&gt;if&lt;/span&gt; task_match
  tasks &lt;span class="Keyword"&gt;=&lt;/span&gt; rake_silent_tasks.&lt;span class="Entity"&gt;grep&lt;/span&gt; &lt;span class="Keyword"&gt;/&lt;/span&gt;&lt;span class="Keyword"&gt;^&lt;/span&gt;&lt;span class="Comment"&gt;&lt;span class="Comment"&gt;#&lt;/span&gt;{Regexp.escape task_match}/&lt;/span&gt;
 
&lt;span class="Comment"&gt;  &lt;span class="Comment"&gt;#&lt;/span&gt; handle namespaces&lt;/span&gt;
  &lt;span class="Keyword"&gt;if&lt;/span&gt; matches &lt;span class="Keyword"&gt;=&lt;/span&gt; task_match.&lt;span class="Entity"&gt;match&lt;/span&gt;(&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;^&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;(&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;[&lt;/span&gt;-&lt;span class="StringRegexpSpecial"&gt;\w&lt;/span&gt;:&lt;span class="StringRegexp"&gt;]&lt;/span&gt;&lt;/span&gt;+:&lt;span class="StringRegexp"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;(&lt;/span&gt;.*&lt;span class="StringRegexp"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;)
    upto_last_colon &lt;span class="Keyword"&gt;=&lt;/span&gt; matches[&lt;span class="Constant"&gt;1&lt;/span&gt;]
    after_match &lt;span class="Keyword"&gt;=&lt;/span&gt; matches[&lt;span class="Constant"&gt;2&lt;/span&gt;]
    tasks &lt;span class="Keyword"&gt;=&lt;/span&gt; tasks.&lt;span class="Entity"&gt;map&lt;/span&gt; { |&lt;span class="Variable"&gt;t&lt;/span&gt;| (t &lt;span class="Keyword"&gt;=~&lt;/span&gt; &lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;^&lt;span class="StringRegexpSpecial"&gt;&lt;span class="StringRegexpSpecial"&gt;#{&lt;/span&gt;&lt;span class="Support"&gt;Regexp&lt;/span&gt;&lt;span class="StringRegexpSpecial"&gt;&lt;span class="StringRegexpSpecial"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;escape&lt;/span&gt;&lt;/span&gt; upto_last_colon&lt;span class="StringRegexpSpecial"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;(&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;[&lt;/span&gt;-&lt;span class="StringRegexpSpecial"&gt;\w&lt;/span&gt;:&lt;span class="StringRegexp"&gt;]&lt;/span&gt;&lt;/span&gt;+&lt;span class="StringRegexp"&gt;)&lt;/span&gt;&lt;/span&gt;$&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;) &lt;span class="Keyword"&gt;?&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="StringEmbeddedSource"&gt;#{&lt;/span&gt;&lt;span class="StringVariable"&gt;&lt;span class="StringVariable"&gt;$&lt;/span&gt;1&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; : t }
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
  puts tasks
&lt;span class="Keyword"&gt;end&lt;/span&gt;
 
exit &lt;span class="Constant"&gt;0&lt;/span&gt;  
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;
  We need to make this executable with:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  chmod &lt;span class="Keyword"&gt;+&lt;/span&gt;x &lt;span class="Keyword"&gt;~&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="StringRegexp"&gt;bin&lt;/span&gt;&lt;span class="StringRegexp"&gt;&lt;span class="StringRegexp"&gt;/&lt;/span&gt;&lt;/span&gt;rake_completion.rb
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;
  Let's go through the code. First comes the 'rake_silent_tasks' top-level method. More on that later.
  Next a couple of checks to ensure we're somewhere where it makes sense to run 'rake' (i.e. a directory with a 'Rakefile' present). Then we check the $COMP_LINE environment variable. This is set by bash and we just need to match it against the string 'rake' at the beginning of the command line. Easy.
&lt;/p&gt;
&lt;p&gt;
  The remaining code is just your average regexp juggling to match the string you enter, e.g. 'rake db:mi[TAB]'.
&lt;/p&gt;
&lt;p&gt;
  What is interesting here is all in the 'rake_silent_tasks' method. In order for lookups to be fast we really want to avoid invoking rake and parse the Rakefile (and all the .task files that are commonly present). 
&lt;/p&gt;
&lt;p&gt;
  The code first checks if we've been running rake+TAB in this directory before and if so, loads an unmarshal the tasks into a Ruby Array. Using Marshal.load/.dump is a big speedup in itself.
&lt;/p&gt;
&lt;p&gt;
  If we need to lookup all the rake tasks from scratch, a full parse of all task defining ruby files is necessary. Previous versions of this code used a backtick invocation of rake like so:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="String"&gt;&lt;span class="String"&gt;`&lt;/span&gt;rake --silent --tasks&lt;span class="String"&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;
  That ouputs the full list of tasks and their descriptions and is quite slow.
&lt;/p&gt;
&lt;p&gt;
  To bypass the necessity for backticks I read through the source code for rake and asked ruby-talk to help out and sure enough, there is a way to get around the necessity to spin off a whole new ruby process, and the following returns a list of tasks as an Array:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;rake&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
  load &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Rakefile&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
  &lt;span class="Support"&gt;Rake&lt;/span&gt;.&lt;span class="Entity"&gt;application&lt;/span&gt;.tasks
&lt;/pre&gt;&lt;/code&gt;  
&lt;p&gt;
  Pretty straightforward, uh? Sure, after the fact it's obvious, but I spent a long while trying to instantiate a new Rake::Application object until told that rake is implemented as a singleton. This snippet will crash so badly that IRB dies and throws you back to the shell:
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Keyword"&gt;require&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;rake&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;
  a &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;Rake&lt;/span&gt;::&lt;span class="Entity"&gt;Application&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;
  a.init
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;
  (maybe it's not even a crash, just plain wrong usage but it's really hard to tell and can be quite confusing...)
&lt;/p&gt;
&lt;p&gt;
  Anyways, retrieving the rake tasks this way is a &lt;strong&gt;lot&lt;/strong&gt; faster. How much?
&lt;/p&gt;
&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;  &lt;span class="Constant"&gt;100&lt;/span&gt; rake task enumerations &lt;span class="Keyword"&gt;for&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;/Users/david/projects/big_rails_app&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
                    user     system      total        real
  backticks     &lt;span class="Constant"&gt;0.160000&lt;/span&gt;   &lt;span class="Constant"&gt;0.330000&lt;/span&gt;  &lt;span class="Constant"&gt;59.680000&lt;/span&gt; ( &lt;span class="Constant"&gt;61.323611&lt;/span&gt;)
  rake direct   &lt;span class="Constant"&gt;0.590000&lt;/span&gt;   &lt;span class="Constant"&gt;0.070000&lt;/span&gt;   &lt;span class="Constant"&gt;0.660000&lt;/span&gt; (  &lt;span class="Constant"&gt;0.676324&lt;/span&gt;)
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;Two orders of magnitude! Yay!&lt;/p&gt;
  
&lt;p&gt;Interestingly, Ruby 1.9 is quite a bit slower than good'ol 1.8:&lt;/p&gt;
  &lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;    &lt;span class="Constant"&gt;100&lt;/span&gt; rake task enumerations &lt;span class="Keyword"&gt;for&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;/Users/david/projects/big_rails_app&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
                      user     system      total        real
    backticks     &lt;span class="Constant"&gt;0.230000&lt;/span&gt;   &lt;span class="Constant"&gt;0.390000&lt;/span&gt;  &lt;span class="Constant"&gt;59.940000&lt;/span&gt; ( &lt;span class="Constant"&gt;61.596335&lt;/span&gt;)
    rake direct   &lt;span class="Constant"&gt;0.960000&lt;/span&gt;   &lt;span class="Constant"&gt;0.110000&lt;/span&gt;   &lt;span class="Constant"&gt;1.070000&lt;/span&gt; (  &lt;span class="Constant"&gt;1.089892&lt;/span&gt;)
  
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;
  While I was investigating the various options to speed up tab completion I first of all grabbed for Ruby 1.9. After a while I discovered that the implementation above never hits the cache and the reason for that is a subtle change in the way the little used String#hash method works.
&lt;/p&gt;
&lt;p&gt;
In 1.8 the hash for a given String is always the same, while in 1.9 the implementation changed to use &lt;a href="http://murmurhash.googlepages.com/"&gt;MurmurHash&lt;/a&gt; and now the hash is identical only within the &lt;strong&gt;same&lt;/strong&gt; ruby process. This change is not documented anywhere to my knowledge and is a deal breaker for ruby scripts used as command line executables (and maybe elsewhere as well).
&lt;/p&gt;
&lt;p&gt;
  I tried to replace the 'Dir.pwd.hash' snippet above with 'Digest::MD5.hexdigest(Dir.pwd)' so it would work under 1.9, but it's a lot slower than Sting#hash, and we're aiming for speed here, so...
&lt;/p&gt;
&lt;p&gt;
  All in all I'm happy with my investigation. As said, learned a lot and in the end I gained a fast-ish rake task tabber script. Many thanks go to Sebastian Hungerecker, Robert Klemme, Ryan Davis and of course to the &lt;a href="http://onrails.org/articles/2006/08/30/namespaces-and-rake-command-completion"&gt;original implementors of the rake tab completion script&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  If you see any other means of speeding this up, please leave a comment! :)
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; fixed escapes in code, as per commenters request (1 Jun 2009)
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/Cb04q55cO0g" height="1" width="1"/&gt;</description>
      <author>David Palm</author>
      <pubDate>Wed, 27 May 2009 16:20:32 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/Cb04q55cO0g/ruby-1-9-isn-t-always-faster-rake-tab-completion-revisited</link>
      <guid isPermaLink="false">http://elctech.com/articles/ruby-1-9-isn-t-always-faster-rake-tab-completion-revisited</guid>
    <feedburner:origLink>http://elctech.com/articles/ruby-1-9-isn-t-always-faster-rake-tab-completion-revisited</feedburner:origLink></item>
    <item>
      <title>First RubyConf.China</title>
      <description>&lt;div class="preface"&gt;

&lt;img src="http://elccore.s3.amazonaws.com/14/737/RubyConfChina.png" alt="Rubyconfchina" /&gt;

&lt;p&gt;The first Ruby conference in Chinae was held at May 21, 2009.  I have had the honor to be the host of the event, and it turned out better than I expected!  Not only was Ruby's Father, &lt;a href="http://en.wikipedia.org/wiki/Yukihiro_Matsumoto" target="_blank"&gt;Matz&lt;/a&gt;, delivered an informative and educational speech, other illustrious developers such as &lt;a href="https://twitter.com/robbinfan" target="_blank"&gt;@robbinfan&lt;/a&gt;, &lt;a href="https://twitter.com/robinlu" target="_blank"&gt;@rubbinlu&lt;/a&gt;, and &lt;a href="http://dreamhead.blogbus.com/" target="_blank"&gt;YeZheng&lt;/a&gt; have also contributed their wealth of knowledge to the conference.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The conference was sponsored by &lt;a href="http://JavaEye.com" target="_blank"&gt;JavaEye.com&lt;/a&gt; (the second largest tech community in China) and &lt;a href="http://ShangHaionRails.org" target="_blank"&gt;ShangHaionRails.org&lt;/a&gt; (a local ruby&amp;rails organization located in ShangHai.)  The conference room was originally booked to seat 200 people, and over 400 have attended this event.  The event was a great success and you can check out more photos and videos on &lt;a href="http://rubyconfchina.org/en" target="_blank"&gt;rubyconfchina.org&lt;/a&gt; and links below.&lt;/p&gt;

&lt;h2&gt;Photos&lt;/h2&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://picasaweb.google.com/rubyac/RubyconfChina" target="_blank"&gt;Photos(by rubyac)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://www.flickr.com/photos/rainux/sets/72157618484203275/" target="_blank"&gt;Photos(by Rainux)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Videos&lt;/h2&gt;
&lt;ul&gt;
    &lt;li&gt;Matz -- Why Ruby?
        &lt;p&gt;&lt;embed type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XOTM2NTkzNjg=/v.swf" allowscriptaccess="sameDomain" height="400" align="middle" quality="high" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;Design Pattern from java to ruby
        &lt;p&gt;&lt;embed type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XOTM1MzU1Mjg=/v.swf" allowscriptaccess="sameDomain" height="400" align="middle" quality="high" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;Deep secret in JavaEye
        &lt;p&gt;&lt;embed type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XOTM1Mzk2MjA=/v.swf" allowscriptaccess="sameDomain" height="400" align="middle" quality="high" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;Ruby and Rails Pitfall
        &lt;p&gt;&lt;embed type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XOTM0NzkwNzI=/v.swf" allowscriptaccess="sameDomain" height="400" align="middle" quality="high" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;Ruby/Rails for Enterprise Development
        &lt;p&gt;&lt;embed type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XOTM1MDg2MzY=/v.swf" allowscriptaccess="sameDomain" height="400" align="middle" quality="high" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;Open Source &amp; Scrum
        &lt;p&gt;&lt;embed type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XOTM1MTQyOTI=/v.swf" allowscriptaccess="sameDomain" height="400" align="middle" quality="high" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;Blue Ruby* A Ruby VM for the ABAP Web Application Server
        &lt;p&gt;&lt;embed type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XOTM1MzI5MTY=/v.swf" allowscriptaccess="sameDomain" height="400" align="middle" quality="high" width="480"&gt;&lt;/embed&gt;&lt;/p&gt;
    &lt;/li&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/UJc5OEGNMZI" height="1" width="1"/&gt;</description>
      <author>Daniel Lv</author>
      <pubDate>Wed, 27 May 2009 07:01:26 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/UJc5OEGNMZI/first-rubyconf-china</link>
      <guid isPermaLink="false">http://elctech.com/articles/first-rubyconf-china</guid>
    <feedburner:origLink>http://elctech.com/articles/first-rubyconf-china</feedburner:origLink></item>
    <item>
      <title>Corrupt Attachments with AR_Mailer</title>
      <description>&lt;div class="preface"&gt;
&lt;h2&gt;AR Mailer and &lt;del&gt;Corrupt&lt;/del&gt; Truncated Attachments&lt;/h2&gt;

&lt;p&gt;After changing our system to send out emails via ar_mailer, the attachments we were sending out were corrupted.&lt;/p&gt;

&lt;p&gt;The "mail" column of the ar_mailer schema is a TEXT column, but that won't work for most attachments, thus, we simply bumped it up to a LONGTEXT (we're using mysql on this project), and everything started working perfectly again.&lt;/p&gt;

&lt;code language="ruby"&gt;&lt;pre class="sunburst"&gt;&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="JEntityNameType"&gt;EmailsMailTextToLongtext&lt;span class="EntityInheritedClass"&gt; &lt;span class="EntityInheritedClass"&gt;&amp;lt;&lt;/span&gt;  ActiveRecord::Migration&lt;/span&gt;&lt;/span&gt;                                                                                                                                           
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.up&lt;/span&gt;                                                                                                                                                                                      
    execute &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;ALTER TABLE emails CHANGE mail mail LONGTEXT&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;                                                                                                                                         
  &lt;span class="Keyword"&gt;end&lt;/span&gt;                                                                                                                                                                                              
                                                                                                                                                                                                   
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.down&lt;/span&gt;                                                                                                                                                                                    
    execute &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;ALTER TABLE emails CHANGE mail mail TEXT&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;                                                                                                                                             
  &lt;span class="Keyword"&gt;end&lt;/span&gt;                                                                                                                                                                                              
&lt;span class="Keyword"&gt;end&lt;/span&gt; 
&lt;/pre&gt;&lt;/code&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/PxIsOixQ9IM" height="1" width="1"/&gt;</description>
      <author>Dylan Stamat</author>
      <pubDate>Fri, 22 May 2009 23:08:36 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/PxIsOixQ9IM/corrupt-attachments-with-ar_mailer</link>
      <guid isPermaLink="false">http://elctech.com/snippets/corrupt-attachments-with-ar_mailer</guid>
    <feedburner:origLink>http://elctech.com/snippets/corrupt-attachments-with-ar_mailer</feedburner:origLink></item>
    <item>
      <title>Multi-part emails sent from a cron job delivered as text/plain only</title>
      <description>&lt;div class="preface"&gt;
&lt;p&gt;
    Had an interesting problem today. We use multipart emails in our client project &lt;a href="http://snapizzi.com"&gt;snapizzi&lt;/a&gt; so users can get pretty little emails if their client supports html. However, we found that any email sent from a cron task was being sent with a mime-type of text/plain, but rendering only the html text. Fugly.
&lt;/p&gt;
&lt;p&gt;
    Turns out this is an active ticket in rails which can be found &lt;a href="https://rails.lighthouseapp.com/projects/8994/tickets/2263-rails-232-breaks-implicit-multipart-actionmailer-tests"&gt;here&lt;/a&gt;, with a patch to fix it that can be found &lt;a href="https://rails.lighthouseapp.com/attachments/108548/0001-Fix-implicit-multipart-mailer-views-when-RAILS_ROOT.patch"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
    We use Rails as a git submodule, so rather than applying the patch and freezing, I just added an &lt;a href="http://elccore.s3.amazonaws.com/3/731/actionmailer_fix.rb"&gt;actionmailer_fix.rb&lt;/a&gt; to my initializers. At least until this patch makes it into Rails.
&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/b7xi8F5R-HU" height="1" width="1"/&gt;</description>
      <author>Daniel LaBare</author>
      <pubDate>Thu, 21 May 2009 23:20:46 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/b7xi8F5R-HU/multi-part-emails-sent-from-a-cron-job-delivered-as-text-plain-only</link>
      <guid isPermaLink="false">http://elctech.com/articles/multi-part-emails-sent-from-a-cron-job-delivered-as-text-plain-only</guid>
    <feedburner:origLink>http://elctech.com/articles/multi-part-emails-sent-from-a-cron-job-delivered-as-text-plain-only</feedburner:origLink></item>
    <item>
      <title>Mozilla Labs Launches JetPack!</title>
      <description>&lt;div class="preface"&gt;
&lt;img src="http://elccore.s3.amazonaws.com/30/730/Jetpack_logo.png" alt="Jetpack_logo" /&gt;
&lt;p&gt;With Mozilla Firefox having such a large following, it is obvious why one would want to extend the browser.  Currently, it requires some intimate knowlege of their API and there is quite a bit of a learning curve when it comes to developing browser plugins (useful ones anyway)&lt;/p&gt;
&lt;p&gt;
    Well, the Mozilla Labs team aims to solve this by creating an API that can be understood by anyone who has ever created a webpage.  According to &lt;a href="https://jetpack.mozillalabs.com/" target="_blank"&gt;their website&lt;/a&gt;:
&lt;hr /&gt;&lt;blockquote&gt;In short, Jetpack is an API for allowing you to write Firefox add-ons using the web technologies you already know.&lt;/blockquote&gt;&lt;hr /&gt;
&lt;/p&gt;
&lt;p&gt;
    The easy to use API is based on Javascript and HTML.  It also comes complete with the &lt;a href="http://jquery.com/" target="_blank"&gt;JQuery library&lt;/a&gt; to do fancy AJAX and Animation effects.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Here is some sample code that you might expect to write to extend the browser.
&lt;/p&gt;&lt;code language="javascript"&gt;&lt;pre class="sunburst"&gt;jetpack.statusBar.append({ html: &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Boom&amp;lt;i&amp;gt;!&amp;lt;/i&amp;gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; });
&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;

&lt;p&gt;Sure, this code just puts the word Boom&lt;em&gt;!&lt;/em&gt; in your status bar.  But this is the most basic example.  One thing I want to point out here is the fact that it accepts HTML markup.  I was able to put the italics tags on an element in the status bar!! You could do all sorts of things, even put an iFrame there (gross).&lt;/p&gt;

&lt;p&gt;While JetPack is still in pre-release, it still packs a punch.  Be sure to check it out! &lt;a href="https://jetpack.mozillalabs.com/" target="_blank"&gt;https://jetpack.mozillalabs.com/&lt;/a&gt;&lt;/p&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ElcCodeFeed/~4/57a5H5sRc78" height="1" width="1"/&gt;</description>
      <author>Brandon Trebitowski</author>
      <pubDate>Thu, 21 May 2009 17:53:16 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/ElcCodeFeed/~3/57a5H5sRc78/mozilla-labs-launches-jetpack</link>
      <guid isPermaLink="false">http://elctech.com/articles/mozilla-labs-launches-jetpack</guid>
    <feedburner:origLink>http://elctech.com/articles/mozilla-labs-launches-jetpack</feedburner:origLink></item>
  </channel>
</rss>
