<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;DUEGRn0_fyp7ImA9WhdUFks.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004</id><updated>2011-10-03T13:47:07.347-05:00</updated><category term="ruby" /><category term="images" /><category term="transcode" /><category term="natural" /><category term="kickstarter" /><category term="javascript" /><category term="sms" /><category term="decorators" /><category term="indent" /><category term="hugamusic" /><category term="selenium" /><category term="documentary" /><category term="gnu" /><category term="wine" /><category term="solutions" /><category term="gang of four" /><category term="pyweek" /><category term="pairing" /><category term="array" /><category term="free culture" /><category term="test" /><category term="scraping" /><category term="crowdfunding" /><category term="TDD" /><category term="agile" /><category term="configuration" /><category term="python" /><category term="society" /><category term="rails" /><category term="haskell" /><category term="codec" /><category term="script" /><category term="video" /><category term="email" /><category term="funds" /><category term="vim" /><category term="code" /><category term="check-in" /><category term="bdd" /><category term="review" /><category term="scripts" /><category term="rake" /><category term="linux" /><category term="change the web" /><category term="xml" /><category term="screen" /><category term="gtd" /><category term="hugacity" /><category term="business" /><category term="interactive" /><category term="olpc" /><category term="socialite" /><category term="patterns" /><category term="smart shuffle" /><category term="commit" /><category term="programming" /><category term="news yc" /><category term="rename" /><category term="lisp" /><category term="hugamovie" /><category term="xo" /><category term="bash" /><category term="game" /><category term="book" /><category term="social actions" /><category term="pana" /><category term="quiz" /><category term="natural wine" /><category term="independent" /><category term="movie" /><category term="text" /><category term="words" /><category term="unix" /><category term="html" /><category term="project euler" /><category term="composition" /><category term="devise" /><category term="design" /><category term="statistics" /><category term="command line" /><category term="testing" /><category term="project" /><category term="texting" /><category term="ide" /><title>clipboarded</title><subtitle type="html">minutes of a programmer</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>49</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Clipboarded" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="clipboarded" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DUEGRn08eyp7ImA9WhdUFks.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-7165488039544413084</id><published>2011-09-29T07:50:00.000-05:00</published><updated>2011-10-03T13:47:07.373-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-03T13:47:07.373-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>partial application in Javascript part 3</title><content type="html">Here is the last part of the videos on partial application. We improve the code from previous videos and make it handle a variable number of parameters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="315" src="http://player.vimeo.com/video/29468055?title=0&amp;amp;byline=0&amp;amp;portrait=0" webkitallowfullscreen="" width="560"&gt;&lt;/iframe&gt;
&lt;br /&gt;
&lt;br /&gt;
In the video, I mention that &lt;i&gt;n&lt;/i&gt; is the number of times we will have to apply partial application before the underlying function is called. That is misleading. The situation is actually a little better than that. &lt;i&gt;n&lt;/i&gt; is really the number of parameters the underlying function cares about. After &lt;i&gt;n&lt;/i&gt; parameters are passed in, the original function will be called. Whether or not we pass in the parameters all at once &lt;i&gt;(a, b, c)&lt;/i&gt; or one at a time.
&lt;br /&gt;
&lt;br /&gt;
Here is the final code:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt; 2 &lt;/span&gt;    &lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt; 3 &lt;/span&gt;        &lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;script&lt;/span&gt;&lt;span class="Identifier"&gt; &lt;/span&gt;&lt;span class="Type"&gt;language&lt;/span&gt;&lt;span class="Identifier"&gt;=&lt;/span&gt;&lt;span class="Constant"&gt;"javascript"&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt; 4 &lt;/span&gt;
&lt;span class="lnr"&gt; 5 &lt;/span&gt;&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;Function&lt;/span&gt;&lt;span class="Special"&gt;.prototype.partial = &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;(&lt;span class="Special"&gt;n&lt;/span&gt;)&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="lnr"&gt; 6 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; original_function = &lt;/span&gt;&lt;span class="Identifier"&gt;this&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt; 7 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; args = &lt;/span&gt;&lt;span class="Identifier"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt; 8 &lt;/span&gt;
&lt;span class="lnr"&gt; 9 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; recursive_partial = &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;()&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="lnr"&gt;10 &lt;/span&gt;&lt;span class="Special"&gt;                    args = args.concat&lt;/span&gt;(&lt;span class="Identifier"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;.slice.apply&lt;/span&gt;(&lt;span class="Identifier"&gt;arguments&lt;/span&gt;))&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;11 &lt;/span&gt;&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Statement"&gt;if&lt;/span&gt;&lt;span class="Special"&gt; &lt;/span&gt;(&lt;span class="Special"&gt;args.length &amp;gt;= n&lt;/span&gt;)&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="lnr"&gt;12 &lt;/span&gt;&lt;span class="Special"&gt;                        &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; original_function.apply&lt;/span&gt;(&lt;span class="Statement"&gt;null&lt;/span&gt;&lt;span class="Special"&gt;, args&lt;/span&gt;)&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;13 &lt;/span&gt;&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;
&lt;span class="lnr"&gt;14 &lt;/span&gt;&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; recursive_partial;&lt;/span&gt;
&lt;span class="lnr"&gt;15 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;16 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; recursive_partial;&lt;/span&gt;
&lt;span class="lnr"&gt;17 &lt;/span&gt;&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;
&lt;span class="lnr"&gt;18 &lt;/span&gt;
&lt;span class="lnr"&gt;19 &lt;/span&gt;&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;&lt;span class="Special"&gt; addTwoNumbers&lt;/span&gt;(&lt;span class="Special"&gt;a,b&lt;/span&gt;)&lt;span class="Identifier"&gt;{&lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; a+b;&lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;
&lt;span class="lnr"&gt;20 &lt;/span&gt;&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;&lt;span class="Special"&gt; addThreeNumbers&lt;/span&gt;(&lt;span class="Special"&gt;a,b,c&lt;/span&gt;)&lt;span class="Identifier"&gt;{&lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; a+b+c;&lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;
&lt;span class="lnr"&gt;21 &lt;/span&gt;
&lt;span class="lnr"&gt;22 &lt;/span&gt;&lt;span class="Special"&gt;        &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;script&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt;23 &lt;/span&gt;
&lt;span class="lnr"&gt;24 &lt;/span&gt;        Partial application #3
&lt;span class="lnr"&gt;25 &lt;/span&gt;
&lt;span class="lnr"&gt;26 &lt;/span&gt;    &lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt;27 &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-7165488039544413084?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/7165488039544413084/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=7165488039544413084" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/7165488039544413084?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/7165488039544413084?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/09/partial-application-in-javascript-part_29.html" title="partial application in Javascript part 3" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEcMR3gyfyp7ImA9WhdUEEk.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-9044833504445772240</id><published>2011-09-26T09:08:00.000-05:00</published><updated>2011-09-26T09:08:06.697-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-26T09:08:06.697-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>partial application in Javascript part 2</title><content type="html">Here is part 2 of the videos on partial application in Javascript. We take the initial prototype and make it handle three parameters.
&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="315" src="http://player.vimeo.com/video/29467871?title=0&amp;amp;byline=0&amp;amp;portrait=0" webkitallowfullscreen="" width="560"&gt;&lt;/iframe&gt;

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here is the code:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt; 2 &lt;/span&gt;    &lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt; 3 &lt;/span&gt;        &lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;script&lt;/span&gt;&lt;span class="Identifier"&gt; &lt;/span&gt;&lt;span class="Type"&gt;language&lt;/span&gt;&lt;span class="Identifier"&gt;=&lt;/span&gt;&lt;span class="Constant"&gt;"javascript"&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt; 4 &lt;/span&gt;
&lt;span class="lnr"&gt; 5 &lt;/span&gt;&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;Function&lt;/span&gt;&lt;span class="Special"&gt;.prototype.partial3 = &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;()&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="lnr"&gt; 6 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; original_function = &lt;/span&gt;&lt;span class="Identifier"&gt;this&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt; 7 &lt;/span&gt;
&lt;span class="lnr"&gt; 8 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; args1 = &lt;/span&gt;&lt;span class="Identifier"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;.slice.apply&lt;/span&gt;(&lt;span class="Identifier"&gt;arguments&lt;/span&gt;)&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt; 9 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;()&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="lnr"&gt;10 &lt;/span&gt;&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; args2 = &lt;/span&gt;&lt;span class="Identifier"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;.slice.apply&lt;/span&gt;(&lt;span class="Identifier"&gt;arguments&lt;/span&gt;)&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;11 &lt;/span&gt;&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;()&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="lnr"&gt;12 &lt;/span&gt;&lt;span class="Special"&gt;                        &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; args3 = &lt;/span&gt;&lt;span class="Identifier"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;.slice.apply&lt;/span&gt;(&lt;span class="Identifier"&gt;arguments&lt;/span&gt;)&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;13 &lt;/span&gt;&lt;span class="Special"&gt;                        &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; original_function.apply&lt;/span&gt;(&lt;span class="Statement"&gt;null&lt;/span&gt;&lt;span class="Special"&gt;, args1.concat&lt;/span&gt;(&lt;span class="Special"&gt;args2&lt;/span&gt;)&lt;span class="Special"&gt;.concat&lt;/span&gt;(&lt;span class="Special"&gt;args3&lt;/span&gt;))&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;14 &lt;/span&gt;&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;
&lt;span class="lnr"&gt;15 &lt;/span&gt;&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;16 &lt;/span&gt;&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="lnr"&gt;17 &lt;/span&gt;
&lt;span class="lnr"&gt;18 &lt;/span&gt;&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;&lt;span class="Special"&gt; addThreeNumbers&lt;/span&gt;(&lt;span class="Special"&gt;a,b,c&lt;/span&gt;)&lt;span class="Identifier"&gt;{&lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; a+b+c;&lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;
&lt;span class="lnr"&gt;19 &lt;/span&gt;
&lt;span class="lnr"&gt;20 &lt;/span&gt;&lt;span class="Special"&gt;        &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;script&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt;21 &lt;/span&gt;
&lt;span class="lnr"&gt;22 &lt;/span&gt;        Partial application #2
&lt;span class="lnr"&gt;23 &lt;/span&gt;
&lt;span class="lnr"&gt;24 &lt;/span&gt;    &lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt;25 &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="lnr"&gt;26 &lt;/span&gt;
&lt;/pre&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-9044833504445772240?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/9044833504445772240/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=9044833504445772240" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/9044833504445772240?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/9044833504445772240?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/09/partial-application-in-javascript-part_7444.html" title="partial application in Javascript part 2" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkUARXg-eip7ImA9WhdVF0g.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-6233854546460818127</id><published>2011-09-23T01:10:00.001-05:00</published><updated>2011-09-23T01:10:44.652-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-23T01:10:44.652-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="video" /><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>partial application in Javascript part 1</title><content type="html">I recently recorded a few videos on partial application in JavaScript. In part 1, I explain what it is and I provide a short code snippet as a first draft. I will build upon the code snippet in the subsequent videos.&lt;br /&gt;&lt;br /&gt;
&lt;iframe src="http://player.vimeo.com/video/29466844?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="560" height="315" frameborder="0" webkitAllowFullScreen allowFullScreen&gt;&lt;/iframe&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
Here is the code that I am using:&lt;br /&gt;
&lt;pre&gt;
&lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Statement"&gt;script&lt;/span&gt;&lt;span class="Identifier"&gt; &lt;/span&gt;&lt;span class="Type"&gt;language&lt;/span&gt;&lt;span class="Identifier"&gt;=&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;javascript&amp;quot;&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;Function&lt;/span&gt;&lt;span class="Special"&gt;.prototype.partial = &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;()&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; original_function = &lt;/span&gt;&lt;span class="Identifier"&gt;this&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; args1 = &lt;/span&gt;&lt;span class="Identifier"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;.slice.apply&lt;/span&gt;(&lt;span class="Identifier"&gt;arguments&lt;/span&gt;)&lt;span class="Special"&gt;;&lt;/span&gt;

&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;()&lt;span class="Identifier"&gt;{&lt;/span&gt;
&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Identifier"&gt;var&lt;/span&gt;&lt;span class="Special"&gt; args2 = &lt;/span&gt;&lt;span class="Identifier"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;.slice.call&lt;/span&gt;(&lt;span class="Identifier"&gt;arguments&lt;/span&gt;)&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="Special"&gt;                    &lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; original_function.apply&lt;/span&gt;(&lt;span class="Statement"&gt;null&lt;/span&gt;&lt;span class="Special"&gt;, args1.concat&lt;/span&gt;(&lt;span class="Special"&gt;args2&lt;/span&gt;))&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="Special"&gt;                &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;
&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;;&lt;/span&gt;

&lt;span class="Special"&gt;            &lt;/span&gt;&lt;span class="Identifier"&gt;function&lt;/span&gt;&lt;span class="Special"&gt; addTwoNumbers&lt;/span&gt;(&lt;span class="Special"&gt;a,b&lt;/span&gt;)&lt;span class="Identifier"&gt;{&lt;/span&gt;&lt;span class="Statement"&gt;return&lt;/span&gt;&lt;span class="Special"&gt; a+b;&lt;/span&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;

&lt;span class="Special"&gt;        &lt;/span&gt;&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;script&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;

        Partial application #1

    &lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;body&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="Identifier"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="Statement"&gt;html&lt;/span&gt;&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;

&lt;/pre&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-6233854546460818127?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/6233854546460818127/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=6233854546460818127" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6233854546460818127?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6233854546460818127?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/09/partial-application-in-javascript-part.html" title="partial application in Javascript part 1" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUMEQXs_eyp7ImA9WhdVF0g.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-3487486811498965498</id><published>2011-09-20T12:25:00.001-05:00</published><updated>2011-09-22T23:50:00.543-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-22T23:50:00.543-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><category scheme="http://www.blogger.com/atom/ns#" term="selenium" /><category scheme="http://www.blogger.com/atom/ns#" term="bdd" /><title>browser testing - looking back</title><content type="html">My last project involved quite a bit of browser testing. Here is a recap video describing lessons learned.&lt;br /&gt;
&lt;br /&gt;
&lt;iframe src="http://player.vimeo.com/video/29206254?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="560" height="315" frameborder="0" webkitAllowFullScreen allowFullScreen&gt;&lt;/iframe&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;Lessons learned&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;/ol&gt;
1- &lt;b&gt;Avoid browser testing: it's too expensive&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .do unit testing&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .do integration testing&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .do view testing (including JavaScript testing)&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .do controller testing&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .build your confidence so you don't have to test using a browser&lt;br /&gt;
&lt;br /&gt;
2- &lt;b&gt;Only test high-level critical bits&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .emulate the user&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .test complete user journeys&lt;br /&gt;
&lt;br /&gt;
3- &lt;b&gt;Manual testing is still needed&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .to test UX&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .to test with multiple browsers&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .to do exploratory testing&lt;br /&gt;
&lt;br /&gt;
4- &lt;b&gt;Non-technical people probably won't be able to write tests w/o help&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .programmers are needed to implements steps interacting with new features&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .that's okay - we like having a job&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;Secondary lessons&lt;/span&gt;&lt;/b&gt; (more technical)&lt;br /&gt;
&lt;br /&gt;
1- &lt;b&gt;Forgiving assertions are useful&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .do not fail the test right away if you can avoid it&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .forgiving assertions provide more coverage and still fail the test if assertion failed&lt;br /&gt;
&lt;br /&gt;
2- &lt;b&gt;Do not test for absence of stuff&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .hard to be sure the assertion is written correctly if the outcome is negative&lt;br /&gt;
&lt;br /&gt;
3- &lt;b&gt;Anchors help with timing issues&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .when the content is dynamic - use anchors&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .wait for something you know to be there before going for the dynamic elements&lt;br /&gt;
&lt;br /&gt;
4- &lt;b&gt;Semantic HTML helps&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .when the HTML is meaningful - the tests are more robust&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .semantic HTML helps avoid brittle xpath expressions&lt;br /&gt;
&lt;br /&gt;
5- &lt;b&gt;Minimize business logic&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .do not test for sorting or any other kind of calculations&lt;br /&gt;
&amp;nbsp;&amp;nbsp; .do not test for things that should be unit-tested&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-3487486811498965498?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/3487486811498965498/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=3487486811498965498" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/3487486811498965498?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/3487486811498965498?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/09/browser-testing-looking-back.html" title="browser testing - looking back" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;C04EQ3kzcSp7ImA9WhdWEUU.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-9176553218266406761</id><published>2011-09-04T19:16:00.003-05:00</published><updated>2011-09-04T19:18:22.789-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-04T19:18:22.789-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gtd" /><title>getting things done</title><content type="html">For a few weeks now I've been using some sort of &lt;b&gt;GTD &lt;/b&gt;system to manage my todos. The GTD -- Getting Things Done -- system is simple but I guess it's got a few&amp;nbsp; things to it so there's &lt;a href="http://www.amazon.com/Getting-Things-Done-Stress-Free-Productivity/dp/0142000280"&gt;a book about it&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
To me, it boils down to how to &lt;b&gt;manage a bunch of todo lists&lt;/b&gt;. I have a handful of todo lists, one for each "project" that I want to get done. And I tag individual todos with labels like &lt;i&gt;@next&lt;/i&gt;, &lt;i&gt;@soon&lt;/i&gt;, &lt;i&gt;@waitin&lt;/i&gt;g, or &lt;i&gt;@reference&lt;/i&gt;. I try to always write down a todo for everything I want to achieve and I sort it into one of the projects.&lt;br /&gt;
&lt;br /&gt;
When I go into planning mode, I tag lots of todos as @next. A quick search for that label will give me my current consolidated todo list. As I get those todos done, I delete them or remove the label and tag some more... Ring around the rosie.&lt;br /&gt;
&lt;br /&gt;
The GTD workflow is easily understood from the following diagram:&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-cjp1wOFwmGA/TmQQyBZx_bI/AAAAAAAAAJY/V7Y5IZpGQ_w/s1600/gtd-workflow.gif" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" id=":current_picnik_image" src="http://2.bp.blogspot.com/-cjp1wOFwmGA/TmQQyBZx_bI/AAAAAAAAAJY/V7Y5IZpGQ_w/s400/gtd-workflow.gif" width="350" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;The GTD workflow - copyright David Allen&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
A lot of software options are available to implement some sort of GTD workflow. But I have settled on the &lt;a href="http://springpadit.com/"&gt;Springpad&lt;/a&gt; Android app. It's got bugs but it's very powerful and it does everything I need for GTD-style management. Hopefully they'll sort out the bugs soon enough.&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-30FFpoUYXiU/TmQTOuPueaI/AAAAAAAAAJc/Y3ekf3kL2hQ/s1600/springpad.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-30FFpoUYXiU/TmQTOuPueaI/AAAAAAAAAJc/Y3ekf3kL2hQ/s400/springpad.png" width="240" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Springpad's home view&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
When I am really totally obsessed about getting things done, I sometimes use the &lt;a href="http://www.pomodorotechnique.com/"&gt;Pomodoro technique&lt;/a&gt;. This one also has a book but frankly, it probably does not deserve that much literature. It's too simple: set a timer for 25 minutes and that's the time you have to get something done. Then take a five-minute break. Rinse and repeat. Everything else is fluff. There is an &lt;a href="https://market.android.com/details?id=it.unibz.pomodroid"&gt;Android app&lt;/a&gt; for that too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-9176553218266406761?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/9176553218266406761/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=9176553218266406761" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/9176553218266406761?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/9176553218266406761?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/09/getting-things-done.html" title="getting things done" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-cjp1wOFwmGA/TmQQyBZx_bI/AAAAAAAAAJY/V7Y5IZpGQ_w/s72-c/gtd-workflow.gif" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUMFRns_fip7ImA9WhdVF0g.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-6646641167300696448</id><published>2011-08-30T19:23:00.000-05:00</published><updated>2011-09-22T23:50:17.546-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-22T23:50:17.546-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="transcode" /><category scheme="http://www.blogger.com/atom/ns#" term="codec" /><title>mjpeg</title><content type="html">I recently discovered &lt;a href="http://www.apple.com/education/itunes-u/"&gt;iTunes U&lt;/a&gt; where one can listen to lectures on a variety of topics. Most files that I downloaded from there worked fine on my linux box and on my phone but some of the files failed to play correctly. The specific error message said &lt;i&gt;Too many audio packets in the buffer.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Here's a pseudo-solution.&lt;br /&gt;
&lt;br /&gt;
The files were .m4b files. Which is a container format -- a variant of mp4. They are usually encoded using an mjpeg encoder where each frame is basically a jpeg image.&lt;br /&gt;
&lt;br /&gt;
So the first step is to extract the audio track as an mp3:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="code"&gt;
&amp;gt; ffmpeg -i input_file.m4b -acodec libmp3lame -ab 192000 out.mp3&lt;/div&gt;
&lt;br /&gt;
Which is a good start. We can now listen to the lecture but we're missing the slides. So we need to extract the jpeg images using the following command line:&lt;br /&gt;
&lt;div class="code"&gt;
&amp;gt; ffmpeg -i input_file.m4b -r 1 frame_%05d.jpg&lt;/div&gt;
&lt;br /&gt;
This will result in a slew of images, one for every second of the lecture. To get rid of the duplicates, I use the following ruby script. It's gross but it mostly works:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="PreProc"&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class="lnr"&gt; 2 &lt;/span&gt;
&lt;span class="lnr"&gt; 3 &lt;/span&gt;&lt;span class="Type"&gt;Dir&lt;/span&gt;.new(&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;.&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;).entries.inject(&lt;span class="Type"&gt;Hash&lt;/span&gt;.new) {|&lt;span class="Identifier"&gt;hash&lt;/span&gt;, &lt;span class="Identifier"&gt;f&lt;/span&gt;|
&lt;span class="lnr"&gt; 4 &lt;/span&gt;
&lt;span class="lnr"&gt; 5 &lt;/span&gt;  &lt;span class="Statement"&gt;if&lt;/span&gt; &lt;span class="Type"&gt;File&lt;/span&gt;.file? f
&lt;span class="lnr"&gt; 6 &lt;/span&gt;    puts &lt;span class="Special"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;removing &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;f&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;"&lt;/span&gt;; &lt;span class="Type"&gt;File&lt;/span&gt;.delete(f) &lt;span class="Statement"&gt;if&lt;/span&gt; hash[&lt;span class="Type"&gt;File&lt;/span&gt;.size? f]
&lt;span class="lnr"&gt; 7 &lt;/span&gt;    hash[&lt;span class="Type"&gt;File&lt;/span&gt;.size? f] = f
&lt;span class="lnr"&gt; 8 &lt;/span&gt;  &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt; 9 &lt;/span&gt;  hash
&lt;span class="lnr"&gt;10 &lt;/span&gt;}&amp;nbsp;&lt;/pre&gt;
&lt;br /&gt;
Run this in the directory where the frames are and you should be on your way. Careful, that script will delete stuff.
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-6646641167300696448?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/6646641167300696448/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=6646641167300696448" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6646641167300696448?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6646641167300696448?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/08/mjpeg.html" title="mjpeg" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkMMR345eSp7ImA9WhdRFUU.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-1424448705097242314</id><published>2011-08-05T18:54:00.002-05:00</published><updated>2011-08-05T18:54:46.021-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-05T18:54:46.021-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>ruby warrior</title><content type="html">&lt;p&gt;There is a fun little project on github called &lt;a href="https://github.com/lbrandy/ruby-warrior"&gt;ruby warrior&lt;/a&gt;. It's an interactive way to learn ruby where you  guide a warrior through levels by implementing a simple function that gets called at every turn. I didn't try to achieve the secondary objectives or anything fancy but here's my solution:&lt;/p&gt;&lt;br /&gt;
&lt;pre&gt;&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt; &lt;span class="Type"&gt;Player&lt;/span&gt;
&lt;span class="lnr"&gt; 2 &lt;/span&gt;  &lt;span class="Identifier"&gt;@@ALL_DIRECTIONS&lt;/span&gt; = [&lt;span class="Constant"&gt;:forward&lt;/span&gt;, &lt;span class="Constant"&gt;:left&lt;/span&gt;, &lt;span class="Constant"&gt;:right&lt;/span&gt;, &lt;span class="Constant"&gt;:backward&lt;/span&gt;]
&lt;span class="lnr"&gt; 3 &lt;/span&gt;
&lt;span class="lnr"&gt; 4 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;play_turn&lt;/span&gt;(warrior)
&lt;span class="lnr"&gt; 5 &lt;/span&gt;    &lt;span class="Identifier"&gt;@warrior&lt;/span&gt; = warrior
&lt;span class="lnr"&gt; 6 &lt;/span&gt;
&lt;span class="lnr"&gt; 7 &lt;/span&gt;    &lt;span class="Statement"&gt;begin&lt;/span&gt;
&lt;span class="lnr"&gt; 8 &lt;/span&gt;      rest_if_safe_to_do_so
&lt;span class="lnr"&gt; 9 &lt;/span&gt;      bind_enemies_if_too_many
&lt;span class="lnr"&gt;10 &lt;/span&gt;      attack_enemies_if_any
&lt;span class="lnr"&gt;11 &lt;/span&gt;      attack_captives_if_present
&lt;span class="lnr"&gt;12 &lt;/span&gt;      move_towards_stairs
&lt;span class="lnr"&gt;13 &lt;/span&gt;    &lt;span class="Statement"&gt;rescue&lt;/span&gt;
&lt;span class="lnr"&gt;14 &lt;/span&gt;      &lt;span class="Statement"&gt;raise&lt;/span&gt; &lt;span class="Statement"&gt;if&lt;/span&gt; &lt;span class="Identifier"&gt;$!&lt;/span&gt;.message != &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;end of turn&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;15 &lt;/span&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;16 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;17 &lt;/span&gt;
&lt;span class="lnr"&gt;18 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;rest_if_safe_to_do_so&lt;/span&gt;
&lt;span class="lnr"&gt;19 &lt;/span&gt;    rest &lt;span class="Statement"&gt;if&lt;/span&gt; safe_to_rest? &lt;span class="Statement"&gt;and&lt;/span&gt; &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.health &amp;lt; &lt;span class="Constant"&gt;20&lt;/span&gt;
&lt;span class="lnr"&gt;20 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;21 &lt;/span&gt;
&lt;span class="lnr"&gt;22 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;bind_enemies_if_too_many&lt;/span&gt;
&lt;span class="lnr"&gt;23 &lt;/span&gt;    directions_with_enemies = &lt;span class="Identifier"&gt;@@ALL_DIRECTIONS&lt;/span&gt;.select {|&lt;span class="Identifier"&gt;d&lt;/span&gt;| &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.feel(d).enemy? }
&lt;span class="lnr"&gt;24 &lt;/span&gt;    bind directions_with_enemies.first &lt;span class="Statement"&gt;if&lt;/span&gt; directions_with_enemies.size &amp;gt; &lt;span class="Constant"&gt;1&lt;/span&gt;
&lt;span class="lnr"&gt;25 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;26 &lt;/span&gt;
&lt;span class="lnr"&gt;27 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;safe_to_rest?&lt;/span&gt;
&lt;span class="lnr"&gt;28 &lt;/span&gt;    &lt;span class="Identifier"&gt;@@ALL_DIRECTIONS&lt;/span&gt;.all? &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;direction&lt;/span&gt;|
&lt;span class="lnr"&gt;29 &lt;/span&gt;      !&lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.feel(direction).enemy?
&lt;span class="lnr"&gt;30 &lt;/span&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;31 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;32 &lt;/span&gt;
&lt;span class="lnr"&gt;33 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;attack_enemies_if_any&lt;/span&gt;
&lt;span class="lnr"&gt;34 &lt;/span&gt;      &lt;span class="Identifier"&gt;@@ALL_DIRECTIONS&lt;/span&gt;.each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;direction&lt;/span&gt;|
&lt;span class="lnr"&gt;35 &lt;/span&gt;        space = &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.feel direction
&lt;span class="lnr"&gt;36 &lt;/span&gt;        attack(direction) &lt;span class="Statement"&gt;if&lt;/span&gt; space.enemy?
&lt;span class="lnr"&gt;37 &lt;/span&gt;      &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;38 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;39 &lt;/span&gt;
&lt;span class="lnr"&gt;40 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;attack_captives_if_present&lt;/span&gt;
&lt;span class="lnr"&gt;41 &lt;/span&gt;    directions_with_captives = &lt;span class="Identifier"&gt;@@ALL_DIRECTIONS&lt;/span&gt;.select {|&lt;span class="Identifier"&gt;d&lt;/span&gt;| &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.feel(d).captive? }
&lt;span class="lnr"&gt;42 &lt;/span&gt;    attack directions_with_captives.first &lt;span class="Statement"&gt;if&lt;/span&gt; !directions_with_captives.empty?
&lt;span class="lnr"&gt;43 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;44 &lt;/span&gt;
&lt;span class="lnr"&gt;45 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;move_towards_stairs&lt;/span&gt;
&lt;span class="lnr"&gt;46 &lt;/span&gt;      walk &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.direction_of_stairs
&lt;span class="lnr"&gt;47 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;48 &lt;/span&gt;
&lt;span class="lnr"&gt;49 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;attack&lt;/span&gt; direction
&lt;span class="lnr"&gt;50 &lt;/span&gt;    &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.attack! direction
&lt;span class="lnr"&gt;51 &lt;/span&gt;    &lt;span class="Statement"&gt;raise&lt;/span&gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;end of turn&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;52 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;53 &lt;/span&gt;
&lt;span class="lnr"&gt;54 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;walk&lt;/span&gt; direction
&lt;span class="lnr"&gt;55 &lt;/span&gt;    &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.walk! direction
&lt;span class="lnr"&gt;56 &lt;/span&gt;    &lt;span class="Statement"&gt;raise&lt;/span&gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;end of turn&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;57 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;58 &lt;/span&gt;
&lt;span class="lnr"&gt;59 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;rest&lt;/span&gt;
&lt;span class="lnr"&gt;60 &lt;/span&gt;    &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.rest!
&lt;span class="lnr"&gt;61 &lt;/span&gt;    &lt;span class="Statement"&gt;raise&lt;/span&gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;end of turn&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;62 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;63 &lt;/span&gt;
&lt;span class="lnr"&gt;64 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;bind&lt;/span&gt; direction
&lt;span class="lnr"&gt;65 &lt;/span&gt;    &lt;span class="Identifier"&gt;@warrior&lt;/span&gt;.bind! direction
&lt;span class="lnr"&gt;66 &lt;/span&gt;    &lt;span class="Statement"&gt;raise&lt;/span&gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;end of turn&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;67 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;68 &lt;/span&gt;
&lt;span class="lnr"&gt;69 &lt;/span&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-1424448705097242314?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/1424448705097242314/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=1424448705097242314" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/1424448705097242314?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/1424448705097242314?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/08/ruby-warrior.html" title="ruby warrior" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkUBQXkycSp7ImA9WhdRFUk.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-3513769159766575019</id><published>2011-07-18T23:51:00.016-05:00</published><updated>2011-08-05T07:44:10.799-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-05T07:44:10.799-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="socialite" /><title>Octopus News goes live</title><content type="html">&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;span style="font-size: small;"&gt;Hello dear comrades!&lt;br /&gt;
&lt;br /&gt;
I have recently published a new website into the public sphere. The name is &lt;a href="http://www.octopusnews.com/" target="_blank"&gt;Octopus News&lt;/a&gt;. Read on to know more...&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif; text-align: center;"&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span style="font-size: small;"&gt;&lt;a href="http://4.bp.blogspot.com/-HKUR0xXzt4k/TiUN4Z1nT8I/AAAAAAAAAJM/CgrQr78vHkI/s1600/logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-HKUR0xXzt4k/TiUN4Z1nT8I/AAAAAAAAAJM/CgrQr78vHkI/s1600/logo.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style="font-size: small;"&gt;&amp;nbsp; " &lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;i&gt;what news?&lt;/i&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt; "&lt;/span&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The Goal&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
The objective is simple: I want to build a small community of avid readers so that we can discuss current affairs and political issues. The website allows you to share online articles and comment on them. Whatever you share with the rest of the group will be voted up according to its merit, and your articles might bubble up to the top -- or not.&lt;br /&gt;
&lt;br /&gt;
To get a feel of what kind of articles you should submit, just look at the ones that are already there. Anything related to international politics is welcome.&lt;br /&gt;
&lt;br /&gt;
For you web-savvy people, the site is very similar in concept to Digg, or Reddit, except the emphasis is on discussion rather than fake karma points.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;How to Contribute&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
Easy. Sign up to &lt;a href="http://www.octopusnews.com/" target="_blank"&gt;Octopus News&lt;/a&gt; and comment on the articles. Vote up the articles that you find the most interesting by clicking the arrow pointing upwards. This will help other people understand what articles are most interesting.&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif; margin-left: 40px;"&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;span style="font-size: small;"&gt;&lt;b&gt;Voting up&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;a href="http://2.bp.blogspot.com/-Gto_FSMK5PM/TiUN89EmM0I/AAAAAAAAAJQ/Dqu6waSoF_A/s1600/vote_up.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-Gto_FSMK5PM/TiUN89EmM0I/AAAAAAAAAJQ/Dqu6waSoF_A/s1600/vote_up.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif; margin-left: 40px; text-align: left;"&gt;
&lt;span style="font-size: small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;span style="font-size: small;"&gt;You can also go to the &lt;a href="http://www.octopusnews.com/submissions/new" target="_blank"&gt;submit page&lt;/a&gt; and submit a story that you want to discuss. To make your life easier, you can drag this &lt;a href="http://draft.blogger.com/blogger.g?blogID=3313530259099615004"&gt;bookmarklet&lt;/a&gt; to your bookmarks toolbar and click on it if you want to submit the article you are currently reading.&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif; margin-left: 40px;"&gt;
&lt;span style="font-size: small;"&gt;&lt;b&gt;Submitting a story&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif; margin-left: 40px; text-align: left;"&gt;
&lt;span style="font-size: small;"&gt;&lt;a href="http://1.bp.blogspot.com/-jOSZj1EGT1E/TiUOGkYCmAI/AAAAAAAAAJU/th88s9-XmzE/s1600/bookmarklet.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-jOSZj1EGT1E/TiUOGkYCmAI/AAAAAAAAAJU/th88s9-XmzE/s1600/bookmarklet.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Verdana,sans-serif;"&gt;
&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Give me feedback!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
Please let me know what you think of the website. Comment on this post, ping me on IM, or buy me a beer.&lt;br /&gt;
&lt;br /&gt;
I know a lot of you read about current affairs and I know it's hard to get into the habit of sharing the good stuff you read so if you have a great idea on how to make submissions to Octopus News easier, let me know.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;Where does the funny name come from?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Good question. The name implies that Octopus News will help you reach out to the world a little more. Using all eight arms... It's also unique and hopefully makes people want to know more about it. Not to mention that the domain name was available. And octopi are funny animals. We'll find a better story once the site makes it big, all right?&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: tahoma,sans-serif; font-size: large;"&gt;&lt;b&gt;How to Contribute as a Developer&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
If you like the website but you think it could use a couple of new features. Well, you are right. Feel free to &lt;a href="https://github.com/matstc/socialite" target="_blank"&gt;clone the codebase&lt;/a&gt; and request a pull. There is a TODO file at the top level if you need inspiration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-3513769159766575019?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/3513769159766575019/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=3513769159766575019" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/3513769159766575019?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/3513769159766575019?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/07/octopus-news-goes-live.html" title="Octopus News goes live" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-HKUR0xXzt4k/TiUN4Z1nT8I/AAAAAAAAAJM/CgrQr78vHkI/s72-c/logo.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;Ck4HSHcyfSp7ImA9WhZRF0g.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-5860089885877348676</id><published>2011-04-13T20:54:00.005-05:00</published><updated>2011-04-13T22:15:39.995-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-13T22:15:39.995-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="socialite" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="devise" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>toggle confirmable on and off</title><content type="html">&lt;p&gt;We are using the &lt;a href="https://github.com/plataformatec/devise"&gt;devise gem&lt;/a&gt; for the authentication of users in &lt;a href="https://github.com/matstc/socialite"&gt;Socialite&lt;/a&gt;. The gem makes it ridiculously easy to manage our users.&lt;/p&gt;&lt;p&gt;One issue we had to solve was a way to toggle on and off the confirmable ability for our user model. Usually, to make the users confirmable or not, you would just add or remove the :confirmable symbol from the list of devise capabilities:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;  devise :database_authenticatable, :registerable, :confirmable,&lt;br /&gt;         :recoverable, :rememberable, :trackable, :validatable&lt;br /&gt;  ...&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This works well usually but we need a way to toggle that capability at runtime. The solution is simple. We created an #after_initialize hook in which we initialized the confirmed_at attribute:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt; &lt;span class="Type"&gt;User&lt;/span&gt; &amp;lt; &lt;span class="Type"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="Type"&gt;Base&lt;/span&gt;&lt;br /&gt;&lt;span class="lnr"&gt; 2 &lt;/span&gt;  devise &lt;span class="Constant"&gt;:database_authenticatable&lt;/span&gt;, &lt;span class="Constant"&gt;:registerable&lt;/span&gt;, &lt;span class="Constant"&gt;:confirmable&lt;/span&gt;,&lt;br /&gt;&lt;span class="lnr"&gt; 3 &lt;/span&gt;         &lt;span class="Constant"&gt;:recoverable&lt;/span&gt;, &lt;span class="Constant"&gt;:rememberable&lt;/span&gt;, &lt;span class="Constant"&gt;:trackable&lt;/span&gt;, &lt;span class="Constant"&gt;:validatable&lt;/span&gt;&lt;br /&gt;&lt;span class="lnr"&gt; 4 &lt;/span&gt;&lt;br /&gt;&lt;span class="lnr"&gt;5 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;setup_default_values&lt;/span&gt;&lt;br /&gt;&lt;span class="lnr"&gt;6 &lt;/span&gt;    &lt;span class="Constant"&gt;self&lt;/span&gt;[&lt;span class="Constant"&gt;:confirmed_at&lt;/span&gt;] ||= &lt;span class="Type"&gt;Time&lt;/span&gt;.now &lt;span class="Statement"&gt;if&lt;/span&gt; !&lt;span class="Type"&gt;AppSettings&lt;/span&gt;.confirm_email_on_registration&lt;br /&gt;&lt;span class="lnr"&gt;7 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="lnr"&gt;8 &lt;/span&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-5860089885877348676?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/5860089885877348676/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=5860089885877348676" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/5860089885877348676?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/5860089885877348676?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/04/toggle-confirmable-on-and-off.html" title="toggle confirmable on and off" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CE8AQn07eip7ImA9WhZSEks.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-5573791597871613028</id><published>2011-03-27T16:54:00.000-05:00</published><updated>2011-03-27T16:54:03.302-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-27T16:54:03.302-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="socialite" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>ajax post, sign in, post, redirect, get</title><content type="html">While working on &lt;a href="https://github.com/pmcfadden/socialite"&gt;socialite&lt;/a&gt;, we ran against the following problem.
&lt;br /&gt;
The users can vote up submissions by clicking the up arrow next to the submissions:
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-PazjAN7VNQo/TY-nYpxBSlI/AAAAAAAAAIc/N6HsY38Oa7c/s1600/vote_up.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="41" src="http://1.bp.blogspot.com/-PazjAN7VNQo/TY-nYpxBSlI/AAAAAAAAAIc/N6HsY38Oa7c/s320/vote_up.png" width="307" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;
The way this usually works is through an ajax request that posts the vote to the server. The Rails view that handles that reads like so:&lt;/p&gt;
&lt;pre&gt;
&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="Special"&gt;-&lt;/span&gt; &lt;span class="Statement"&gt;if&lt;/span&gt; current_user.nil? &lt;span class="Statement"&gt;or&lt;/span&gt; current_user.can_vote_for(submission)
&lt;span class="lnr"&gt; 2 &lt;/span&gt;  &lt;span class="Special"&gt;=&lt;/span&gt; link_to vote_up_path(&lt;span class="Constant"&gt;:id&lt;/span&gt; =&amp;gt; submission.id), &lt;span class="Constant"&gt;:method&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;:post&lt;/span&gt;, &lt;span class="Constant"&gt;:remote&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;true&lt;/span&gt;, &lt;span class="Constant"&gt;:class&lt;/span&gt; =&amp;gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;vote-up&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;:id&lt;/span&gt; =&amp;gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;voting-booth-&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;submission.id&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;:title&lt;/span&gt; =&amp;gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;vote up&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt; &lt;span class="Statement"&gt;do&lt;/span&gt;
&lt;span class="lnr"&gt; 3 &lt;/span&gt;    != icon 'circle-arrow-n'
&lt;span class="lnr"&gt; 4 &lt;/span&gt;
&lt;span class="lnr"&gt; 5 &lt;/span&gt;&lt;span class="Special"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;
&lt;span class="lnr"&gt; 6 &lt;/span&gt;  &lt;span class="Special"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;:class&lt;/span&gt; =&amp;gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;score-bracket&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt; 7 &lt;/span&gt;  &lt;span class="Special"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;:class&lt;/span&gt; =&amp;gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;score&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;, &lt;span class="Constant"&gt;:id&lt;/span&gt; =&amp;gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;score-for-submission-&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;submission.id&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;=&lt;/span&gt; submission.score.to_i
&lt;span class="lnr"&gt; 8 &lt;/span&gt;  &lt;span class="Special"&gt;%&lt;/span&gt;&lt;span class="Statement"&gt;span&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;:class&lt;/span&gt; =&amp;gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;score-bracket&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;]&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt; 9 &lt;/span&gt;
&lt;span class="lnr"&gt;10 &lt;/span&gt;:javascript
&lt;span class="lnr"&gt;11 &lt;/span&gt;  $(document).ready(function(){
&lt;span class="lnr"&gt;12 &lt;/span&gt;    $('#voting-booth-#{submission.id}').bind('ajax:success', function(obj, data){
&lt;span class="lnr"&gt;13 &lt;/span&gt;      data = eval(&amp;quot;(&amp;quot; + data + &amp;quot;)&amp;quot;);
&lt;span class="lnr"&gt;14 &lt;/span&gt;      $('#score-for-submission-' + data['id']).text(data['score']);
&lt;span class="lnr"&gt;15 &lt;/span&gt;      $('#voting-booth-' + data['id']).addClass('invisible');
&lt;span class="lnr"&gt;16 &lt;/span&gt;    });
&lt;span class="lnr"&gt;17 &lt;/span&gt;  });
&lt;/pre&gt;

&lt;p&gt;Everything works fine with this setup, except when the user is not signed in. In that case, we could hide the up arrow but that's not very user-friendly. We really want to show things like that so the users understand what they are allowed or expected to do.&lt;/p&gt;
&lt;p&gt;Usually, when a user that is not registered clicks a link that would require him to be registered; the server will remember that link, show a sign in page, and then redirect to that link. We cannot do that in our case because the link is a post. Further, it's an ajax post so the rendered content makes no sense outside of its usual page.&lt;/p&gt;
&lt;p&gt;So the solution we came up with is to remember the current page as the user clicks the arrow and also to remember the post request -- both pieces of information are stored in the session. Then, after the user signs in or signs up, we artificially execute the post before redirecting to the original page -- the one where they triggered the post request.&lt;/p&gt;
&lt;p&gt;The first thing we have to do is remember the post request when the user is not signed in. We do that by adding the following to our application controller:&lt;/p&gt;
&lt;pre&gt;
&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt; &lt;span class="Type"&gt;ApplicationController&lt;/span&gt; &amp;lt; &lt;span class="Type"&gt;ActionController&lt;/span&gt;::&lt;span class="Type"&gt;Base&lt;/span&gt;
&lt;span class="lnr"&gt; 2 &lt;/span&gt;
&lt;span class="lnr"&gt; 3 &lt;/span&gt;  &lt;span class="Comment"&gt;# this before filter will save an attempted post request for later execution after the user is authenticated&lt;/span&gt;
&lt;span class="lnr"&gt; 4 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;save_post_before_authenticating&lt;/span&gt;
&lt;span class="lnr"&gt; 5 &lt;/span&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; request.env[&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;warden&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;].unauthenticated? &lt;span class="Statement"&gt;and&lt;/span&gt; request.post?
&lt;span class="lnr"&gt; 6 &lt;/span&gt;      logger.info &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;Will save the POST request for later execution&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt; 7 &lt;/span&gt;      session[&lt;span class="Constant"&gt;:pre_sign_in_post&lt;/span&gt;] = {&lt;span class="Constant"&gt;:controller&lt;/span&gt; =&amp;gt; controller_name, &lt;span class="Constant"&gt;:action&lt;/span&gt; =&amp;gt; action_name, &lt;span class="Constant"&gt;:params&lt;/span&gt; =&amp;gt; params.dup}
&lt;span class="lnr"&gt; 8 &lt;/span&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt; 9 &lt;/span&gt;
&lt;span class="lnr"&gt;10 &lt;/span&gt;    authenticate_user!
&lt;span class="lnr"&gt;11 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;12 &lt;/span&gt;
&lt;span class="lnr"&gt;13 &lt;/span&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here we are using &lt;i&gt;warden&lt;/i&gt;, the underlying library behind the &lt;a href="https://github.com/plataformatec/devise"&gt;devise&lt;/a&gt; gem.&lt;/p&gt;
&lt;p&gt; The &lt;i&gt;save_post_before_authenticating&lt;/i&gt; method is added as a before filter to the &lt;i&gt;vote_up&lt;/i&gt; action:&lt;/p&gt;
&lt;pre&gt;
  before_filter :save_post_before_authenticating, :only =&gt; [:vote_up]
&lt;/pre&gt;
&lt;p&gt;Next, we have to handle the 401 response sent back from the server when a vote takes place for a user that is not signed in. The javascript code reads like that:&lt;/p&gt;
&lt;pre&gt;
  $(document).ready(function(){
    $(document.body).bind('ajax:error', function(status, xhr, err){
      if(xhr.status == 401){
        window.location = '/sign_in_then_redirect?current_url=' + escape(window.location)
      }
    });
  });
&lt;/pre&gt;
&lt;p&gt;The URL we are now reaching out to (&lt;i&gt;sign_in_then_redirect&lt;/i&gt;) will remember the current page and redirect to the sign in page:&lt;/p&gt;
&lt;pre&gt;
&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt; &lt;span class="Type"&gt;ApplicationController&lt;/span&gt; &amp;lt; &lt;span class="Type"&gt;ActionController&lt;/span&gt;::&lt;span class="Type"&gt;Base&lt;/span&gt;
&lt;span class="lnr"&gt; 2 &lt;/span&gt;
&lt;span class="lnr"&gt; 3 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;sign_in_then_redirect&lt;/span&gt;
&lt;span class="lnr"&gt; 4 &lt;/span&gt;    flash[&lt;span class="Constant"&gt;:alert&lt;/span&gt;] = &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;Please sign in first.&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt; 5 &lt;/span&gt;    session[&lt;span class="Constant"&gt;:last_get_url&lt;/span&gt;] = params[&lt;span class="Constant"&gt;:current_url&lt;/span&gt;]
&lt;span class="lnr"&gt; 6 &lt;/span&gt;    redirect_to new_session_url(&lt;span class="Constant"&gt;:user&lt;/span&gt;)
&lt;span class="lnr"&gt; 7 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt; 8 &lt;/span&gt;
&lt;span class="lnr"&gt; 9 &lt;/span&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;At this point, the user will sign in and we will need to execute the saved post request and redirect them to their previous location. We have all the information we need but artificially executing the post request is tricky. We need to hack together a few things. First off, the &lt;i&gt;after_sign_in_path_for&lt;/i&gt; is a method from the devise gem that is executed when trying to figure out where to redirect the users after they sign in. So we hook into that method and do some request processing. We instantiate the controller that would have been created by the post request and we call its action method. Before we call the action method though, we have to make sure that &lt;i&gt;params&lt;/i&gt; and &lt;i&gt;request&lt;/i&gt; actually point to the old post params and request.&lt;/p&gt;
&lt;p&gt;As a bonus, we replace the flash notice with whatever is in &lt;i&gt;flash[:pre_sign_in_notice]&lt;/i&gt; so the vote up action can reassure the user that their vote was taken into account.&lt;/p&gt;
&lt;p&gt;The code for these two methods is as follows:&lt;/p&gt;
&lt;pre&gt;
&lt;span class="lnr"&gt; 1 &lt;/span&gt;&lt;span class="PreProc"&gt;class&lt;/span&gt; &lt;span class="Type"&gt;ApplicationController&lt;/span&gt; &amp;lt; &lt;span class="Type"&gt;ActionController&lt;/span&gt;::&lt;span class="Type"&gt;Base&lt;/span&gt;
&lt;span class="lnr"&gt; 2 &lt;/span&gt;
&lt;span class="lnr"&gt; 3 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;after_sign_in_path_for&lt;/span&gt; resource_or_scope
&lt;span class="lnr"&gt; 4 &lt;/span&gt;    last_get_url = session[&lt;span class="Constant"&gt;:last_get_url&lt;/span&gt;]
&lt;span class="lnr"&gt; 5 &lt;/span&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; last_get_url.nil?
&lt;span class="lnr"&gt; 6 &lt;/span&gt;      &lt;span class="Statement"&gt;return&lt;/span&gt; &lt;span class="Statement"&gt;super&lt;/span&gt;
&lt;span class="lnr"&gt; 7 &lt;/span&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt; 8 &lt;/span&gt;
&lt;span class="lnr"&gt; 9 &lt;/span&gt;    &lt;span class="Comment"&gt;# if a post request was saved in the session then we execute it -- see #save_post_before_authenticating&lt;/span&gt;
&lt;span class="lnr"&gt;10 &lt;/span&gt;    execute_saved_post_request &lt;span class="Statement"&gt;if&lt;/span&gt; session[&lt;span class="Constant"&gt;:pre_sign_in_post&lt;/span&gt;]
&lt;span class="lnr"&gt;11 &lt;/span&gt;
&lt;span class="lnr"&gt;12 &lt;/span&gt;    last_get_url
&lt;span class="lnr"&gt;13 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;14 &lt;/span&gt;
&lt;span class="lnr"&gt;15 &lt;/span&gt;  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;execute_saved_post_request&lt;/span&gt;
&lt;span class="lnr"&gt;16 &lt;/span&gt;    logger.info &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;Executing the saved POST request before redirecting&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;17 &lt;/span&gt;
&lt;span class="lnr"&gt;18 &lt;/span&gt;    &lt;span class="Statement"&gt;begin&lt;/span&gt;
&lt;span class="lnr"&gt;19 &lt;/span&gt;      class_name = session[&lt;span class="Constant"&gt;:pre_sign_in_post&lt;/span&gt;][&lt;span class="Constant"&gt;:controller&lt;/span&gt;].capitalize + &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;Controller&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;20 &lt;/span&gt;      controller_instance = class_name.constantize.new
&lt;span class="lnr"&gt;21 &lt;/span&gt;
&lt;span class="lnr"&gt;22 &lt;/span&gt;      current_request = request
&lt;span class="lnr"&gt;23 &lt;/span&gt;      saved_params = session[&lt;span class="Constant"&gt;:pre_sign_in_post&lt;/span&gt;][&lt;span class="Constant"&gt;:params&lt;/span&gt;]
&lt;span class="lnr"&gt;24 &lt;/span&gt;      metaclass = (&lt;span class="PreProc"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; controller_instance; &lt;span class="Constant"&gt;self&lt;/span&gt;; &lt;span class="PreProc"&gt;end&lt;/span&gt;)
&lt;span class="lnr"&gt;25 &lt;/span&gt;
&lt;span class="lnr"&gt;26 &lt;/span&gt;      metaclass.send(&lt;span class="Constant"&gt;:define_method&lt;/span&gt;, &lt;span class="Constant"&gt;:request&lt;/span&gt;) { &lt;span class="Statement"&gt;return&lt;/span&gt; current_request }
&lt;span class="lnr"&gt;27 &lt;/span&gt;      metaclass.send(&lt;span class="Constant"&gt;:define_method&lt;/span&gt;, &lt;span class="Constant"&gt;:params&lt;/span&gt;) { &lt;span class="Statement"&gt;return&lt;/span&gt; saved_params }
&lt;span class="lnr"&gt;28 &lt;/span&gt;
&lt;span class="lnr"&gt;29 &lt;/span&gt;      controller_instance.send(session[&lt;span class="Constant"&gt;:pre_sign_in_post&lt;/span&gt;][&lt;span class="Constant"&gt;:action&lt;/span&gt;])
&lt;span class="lnr"&gt;30 &lt;/span&gt;      flash[&lt;span class="Constant"&gt;:notice&lt;/span&gt;] = flash[&lt;span class="Constant"&gt;:pre_sign_in_notice&lt;/span&gt;] &lt;span class="Statement"&gt;if&lt;/span&gt; flash[&lt;span class="Constant"&gt;:pre_sign_in_notice&lt;/span&gt;]
&lt;span class="lnr"&gt;31 &lt;/span&gt;    &lt;span class="Statement"&gt;rescue&lt;/span&gt;
&lt;span class="lnr"&gt;32 &lt;/span&gt;      logger.error &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;An error occurred trying to execute the saved POST request: &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;&lt;span class="Identifier"&gt;$!&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="lnr"&gt;33 &lt;/span&gt;      flash[&lt;span class="Constant"&gt;:alert&lt;/span&gt;] = &lt;span class="Identifier"&gt;$!&lt;/span&gt;.message
&lt;span class="lnr"&gt;34 &lt;/span&gt;    &lt;span class="Statement"&gt;ensure&lt;/span&gt;
&lt;span class="lnr"&gt;35 &lt;/span&gt;      session[&lt;span class="Constant"&gt;:pre_sign_in_post&lt;/span&gt;] = &lt;span class="Constant"&gt;nil&lt;/span&gt;
&lt;span class="lnr"&gt;36 &lt;/span&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;37 &lt;/span&gt;  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="lnr"&gt;38 &lt;/span&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The above solution is far from generic but it works well for socialite. Among other things, if the action method from the saved post request calls out to &lt;i&gt;render&lt;/i&gt;, this solution will not work. At the very least, the &lt;i&gt;render&lt;/i&gt; call would have to be stubbed.&lt;/p&gt;
&lt;p&gt;Feel free to have a better look at the code through the &lt;a href="https://github.com/pmcfadden/socialite"&gt;github&lt;/a&gt; page. And let me know if you have suggestions to improve this solution.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-5573791597871613028?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/5573791597871613028/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=5573791597871613028" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/5573791597871613028?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/5573791597871613028?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/03/ajax-post-sign-in-post-redirect-get.html" title="ajax post, sign in, post, redirect, get" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-PazjAN7VNQo/TY-nYpxBSlI/AAAAAAAAAIc/N6HsY38Oa7c/s72-c/vote_up.png" height="72" width="72" /><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;CUYBRHsycSp7ImA9Wx9aE0U.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-6563066651383593445</id><published>2011-03-05T21:45:00.000-06:00</published><updated>2011-03-05T21:45:55.599-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-05T21:45:55.599-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="socialite" /><title>socialite</title><content type="html">We just started working on a  CMS for social news websites. I will post more about it later but here's the link to the github project: &lt;a href="https://github.com/pmcfadden/socialite"&gt;Socialite&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-6563066651383593445?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/6563066651383593445/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=6563066651383593445" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6563066651383593445?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6563066651383593445?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/03/socialite.html" title="socialite" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUUBRHsycSp7ImA9Wx9VEE0.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-5824428908800928994</id><published>2011-01-25T20:00:00.000-06:00</published><updated>2011-01-25T20:00:55.599-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-25T20:00:55.599-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="pana" /><category scheme="http://www.blogger.com/atom/ns#" term="script" /><category scheme="http://www.blogger.com/atom/ns#" term="smart shuffle" /><title>smart shuffle for pana</title><content type="html">I wrote a script some time ago to shuffle a playlist not only by randomizing the order of the songs but also by spreading out songs from the same artist.&lt;br /&gt;
The script was written for Amarok but I now use a forked version of it called Pana. Here is the new &lt;a href="https://docs.google.com/leaf?id=0Bxk9j0UnzN61ZjIyZTUzYzctNWQwNi00ZmNhLTg4OTktY2Q5OWI2YzMwNzM3&amp;amp;hl=en_GB"&gt;script&lt;/a&gt; recompiled for Pana.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-5824428908800928994?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/5824428908800928994/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=5824428908800928994" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/5824428908800928994?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/5824428908800928994?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2011/01/smart-shuffle-for-pana.html" title="smart shuffle for pana" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUQEQHg_fip7ImA9Wx9TGE4.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-7000386840086467458</id><published>2010-11-26T22:47:00.001-06:00</published><updated>2010-11-26T22:48:21.646-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-26T22:48:21.646-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="documentary" /><category scheme="http://www.blogger.com/atom/ns#" term="natural wine" /><category scheme="http://www.blogger.com/atom/ns#" term="kickstarter" /><category scheme="http://www.blogger.com/atom/ns#" term="movie" /><title>Our Kickstarter project just launched!</title><content type="html">Our documentary project moves forward. We just published our Kickstarter trailer and launched our project page! You can back us up on Kickstarter.&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;iframe frameborder="0" height="410px" src="http://www.kickstarter.com/projects/715926796/natural-wine-in-california/widget/video.html" width="480px"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-7000386840086467458?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/7000386840086467458/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=7000386840086467458" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/7000386840086467458?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/7000386840086467458?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2010/11/our-kickstarter-project-just-launched.html" title="Our Kickstarter project just launched!" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C04DRnk6eCp7ImA9Wx5bF08.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-295351871711937911</id><published>2010-11-02T13:19:00.000-05:00</published><updated>2010-11-02T13:19:37.710-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-02T13:19:37.710-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="documentary" /><category scheme="http://www.blogger.com/atom/ns#" term="wine" /><category scheme="http://www.blogger.com/atom/ns#" term="natural" /><category scheme="http://www.blogger.com/atom/ns#" term="movie" /><title>making a movie</title><content type="html">&lt;p&gt;These days I'm spending most of my time shooting a &lt;a href="http://www.winobrothers.com"&gt;documentary&lt;/a&gt; with my brother. It's about natural wine in California.&lt;/p&gt;

&lt;p&gt;Some short samples of &lt;a href="http://www.vimeo.com/user5049668/videos"&gt;interviews&lt;/a&gt; are already available on our vimeo page.&lt;/p&gt;
&lt;p&gt;As well as some &lt;a href="http://www.flickr.com/photos/winobrothers/"&gt;pictures&lt;/a&gt; on our flickr page!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-295351871711937911?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/295351871711937911/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=295351871711937911" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/295351871711937911?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/295351871711937911?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2010/11/making-movie.html" title="making a movie" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0YGSX49eip7ImA9Wx5RE0Q.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-3963153445501916323</id><published>2010-08-21T08:58:00.000-05:00</published><updated>2010-08-21T08:58:48.062-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-21T08:58:48.062-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="crowdfunding" /><category scheme="http://www.blogger.com/atom/ns#" term="independent" /><category scheme="http://www.blogger.com/atom/ns#" term="funds" /><category scheme="http://www.blogger.com/atom/ns#" term="project" /><title>crowd funding</title><content type="html">&lt;p&gt;fundable.com died a controversial death but a couple of new websites have sprung up around the same concept:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.kickstarter.com"&gt;Kickstarter&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.indiegogo.com/"&gt;Indie Go Go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The concept is simple: each project sets a deadline and a dollar amount to raise by that deadline. Other users then pledge to donate to that project and if the goal is reached, money changes hands and the hip entrepreneurs get all the money. If the goal is not reached, the backers keep their dollars.&lt;/p&gt;

&lt;p&gt;Each project will post a list of rewards that they promise to give to a backer depending on how much is donated. For instance, 5 bucks might get you a mention in the credits at the end of a documentary. 30 bucks might get you an online link to download the movie.&lt;/p&gt;

&lt;p&gt;You could start by looking at &lt;a href="http://kck.st/9IQTfQ"&gt;Sparrow Songs&lt;/a&gt; or &lt;a href="http://kck.st/amcsLz"&gt;Below New York&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-3963153445501916323?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/3963153445501916323/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=3963153445501916323" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/3963153445501916323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/3963153445501916323?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2010/08/crowd-funding.html" title="crowd funding" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0YFRn09fip7ImA9WxFSGUk.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-6323533803563591714</id><published>2010-04-22T10:04:00.004-05:00</published><updated>2010-04-22T10:11:57.366-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-22T10:11:57.366-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="rake" /><title>skip any rake dependency</title><content type="html">Here is an easy way to skip a rake dependency:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;rake skip[taskname] othertask&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The following code makes that possible:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;desc 'Skip task in parameter if it is found to be a dependency'&lt;br /&gt;task :skip, :task do |t, args|&lt;br /&gt;  task_name = args[:task]&lt;br /&gt;  Rake::Task.tasks.each do |t|&lt;br /&gt;    t.prerequisites.reject!{|prerequisite| prerequisite == task_name}&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-6323533803563591714?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/6323533803563591714/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=6323533803563591714" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6323533803563591714?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6323533803563591714?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2010/04/skip-any-rake-dependency.html" title="skip any rake dependency" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0UNSHw8eip7ImA9WxBQFUw.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-4930491372421034880</id><published>2010-01-14T14:44:00.008-06:00</published><updated>2010-01-14T17:21:39.272-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-14T17:21:39.272-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="book" /><title>javascript: the good parts :: review</title><content type="html">&lt;p&gt;I recommend &lt;a href="http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1263511282&amp;sr=8-1"&gt;Douglas Crockford's book&lt;/a&gt; to anyone who wants to learn more about JavaScript. It really consolidated my knowledge of the language. The book is short and enjoyable. The author comes off as really credible which is important as the book makes quite a few recommendations on proper usage and style. Here are a few notes that I took while reading the book.&lt;/p&gt;&lt;h4&gt;The prototype chain&lt;/h4&gt;&lt;p&gt;The prototype is only used when retrieving values. Setting a property always sets it on the receiver directly. To know if the receiver has a property without looking at the prototype, use #hasOwnProperty.&lt;/p&gt;&lt;h4&gt;Function calls&lt;/h4&gt;&lt;p&gt;Every function has access to two magic objects: &lt;i&gt;this&lt;/i&gt; and &lt;i&gt;arguments&lt;/i&gt;. &lt;i&gt;This&lt;/i&gt; is a link to the current object and its value depends on the invocation pattern of the function. &lt;i&gt;Arguments&lt;/i&gt; is an array-like object containing all the arguments passed in to the function.&lt;/p&gt;&lt;p&gt;There are four invocation patterns:&lt;ul&gt;&lt;li&gt;As a method: when called on a receiver object, &lt;i&gt;this&lt;/i&gt; represents the receiver&lt;/li&gt;&lt;li&gt;As a function: when called without a receiver, the &lt;i&gt;this&lt;/i&gt; pointer points to the global object&lt;/li&gt;&lt;li&gt;As a constructor: when invoked with the &lt;i&gt;new&lt;/i&gt; keyword, a new object is created using the function's prototype. &lt;i&gt;This&lt;/i&gt; points to that new object.&lt;/li&gt;&lt;li&gt;Using #apply: in this case, the &lt;i&gt;this&lt;/i&gt; pointer is explicit and passed in to #apply.&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;h4&gt;Partial application in JavaScript&lt;/h4&gt;&lt;p&gt;Here is a clever snippet from the book that allows function application.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;Function.prototype.curry = function(){&lt;br /&gt;  var slice = Array.prototype.slice;&lt;br /&gt;  var args = slice.apply(arguments);&lt;br /&gt;  var that = this;&lt;br /&gt;  &lt;br /&gt;  return function(){&lt;br /&gt;    return that.apply(null, args.concat(slice.apply(arguments)));&lt;br /&gt;  };&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;You can then use it like this:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt;&gt;&gt; function add(a,b) {return a + b;}&lt;br /&gt;&gt;&gt;&gt; add.curry(1)(2)&lt;br /&gt;3&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Recommendations and gotchas&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;JavaScript does not have block scope&lt;/li&gt;&lt;li&gt;Avoid the use of 'new'&lt;/li&gt;&lt;li&gt;Always pass in the radix parameter to #parseInt&lt;/li&gt;&lt;li&gt;Always use === and !==, not == or !=&lt;/li&gt;&lt;li&gt;Avoid the use of 'with', use a local variable instead&lt;/li&gt;&lt;li&gt;Avoid the use of 'void'&lt;/li&gt;&lt;li&gt;Avoid the use of typed wrappers like new Boolean, new String, or new Number&lt;/li&gt;&lt;li&gt;All characeters are 16-bits wide&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-4930491372421034880?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/4930491372421034880/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=4930491372421034880" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/4930491372421034880?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/4930491372421034880?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2010/01/javascript-good-parts-review.html" title="javascript: the good parts :: review" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0QDRHs-fSp7ImA9WxBQEUs.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-520915205108442041</id><published>2010-01-10T17:10:00.002-06:00</published><updated>2010-01-10T17:16:15.555-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-10T17:16:15.555-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="texting" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="sms" /><title>textonyms</title><content type="html">&lt;p&gt;I was interested in textonyms -- words that can be represented by the same digits when texting. Rotating through the list of possible words for a certain input, a phone will turn &lt;i&gt;lips&lt;/i&gt; into &lt;i&gt;kiss&lt;/i&gt;. Or &lt;i&gt;good&lt;/i&gt; into &lt;i&gt;home&lt;/i&gt;. &lt;i&gt;Book&lt;/i&gt; becomes &lt;i&gt;cool&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;So I wrote the following script to extract textonyms from a list of words. It should be used on a text file containing one word per line.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#!/usr/bin/env ruby &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;populate&lt;/span&gt; dictfile&lt;br /&gt;  digits2words = &lt;span class="Type"&gt;Hash&lt;/span&gt;.new {|&lt;span class="Identifier"&gt;hash&lt;/span&gt;, &lt;span class="Identifier"&gt;key&lt;/span&gt;| hash[key] = []}&lt;br /&gt;&lt;br /&gt;  &lt;span class="Type"&gt;File&lt;/span&gt;::open(dictfile){|&lt;span class="Identifier"&gt;file&lt;/span&gt;|&lt;br /&gt;    file.each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;line&lt;/span&gt;|&lt;br /&gt;      digits = line.chomp!.split(&lt;span class="Special"&gt;//&lt;/span&gt;).map &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;char&lt;/span&gt;| &lt;span class="Type"&gt;CHAR_TO_DIGIT&lt;/span&gt;[char.downcase.to_sym] &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;      digits2words[digits.to_s] &amp;lt;&amp;lt; line&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  digits2words.each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;key&lt;/span&gt;, &lt;span class="Identifier"&gt;values&lt;/span&gt;|&lt;br /&gt;    puts &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;key&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;\t&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;values.size&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;\t&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;values.join &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt; &lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;CHAR_TO_DIGIT&lt;/span&gt; = {&lt;br /&gt;  &lt;span class="Constant"&gt;:a&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;2&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:b&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;2&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:c&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;2&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:d&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;3&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:e&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;3&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:f&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;3&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:g&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:h&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:i&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:j&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;5&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:k&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;5&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:l&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;5&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:m&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;6&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:n&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;6&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:o&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;6&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:p&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;7&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:q&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;7&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:r&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;7&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:s&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;7&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:t&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:u&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:v&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:w&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;9&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:x&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;9&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:y&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;9&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Constant"&gt;:z&lt;/span&gt; =&amp;gt; &lt;span class="Constant"&gt;9&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;if&lt;/span&gt; &lt;span class="Constant"&gt;__FILE__&lt;/span&gt; == &lt;span class="Identifier"&gt;$0&lt;/span&gt;&lt;br /&gt;  &lt;span class="Statement"&gt;if&lt;/span&gt; !&lt;span class="Identifier"&gt;ARGV&lt;/span&gt;.empty?&lt;br /&gt;    populate(&lt;span class="Identifier"&gt;ARGV&lt;/span&gt;[&lt;span class="Constant"&gt;0&lt;/span&gt;])&lt;br /&gt;  &lt;span class="Statement"&gt;else&lt;/span&gt;&lt;br /&gt;    puts &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;specify a file name&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-520915205108442041?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/520915205108442041/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=520915205108442041" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/520915205108442041?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/520915205108442041?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2010/01/textonyms.html" title="textonyms" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;C0UAQX85eSp7ImA9WxNaGEw.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-2919971192753929808</id><published>2009-12-02T21:22:00.011-06:00</published><updated>2009-12-02T21:34:00.121-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-02T21:34:00.121-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="words" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>urban dictionary's greatest hits</title><content type="html">&lt;p&gt;I was curious about what words were the most popular on &lt;a href="http://urbandictionary.com/"&gt;urbandictionary.com&lt;/a&gt;. So I scraped the &lt;i&gt;popular&lt;/i&gt; section for each letter in the alphabet and came up with the following table where the ranking is based on the number of upvotes. I didn't want to have my blog associated with any of the words below and I didn't want to give backlinks to the urban dictionary so here's an image of my results.&lt;/p&gt;

&lt;div style="text-align:center"&gt;
&lt;a href="http://3.bp.blogspot.com/_c-z10zbSfTE/SxctePmVmgI/AAAAAAAAAGk/hN14beGHwjs/s1600/results.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_c-z10zbSfTE/SxctePmVmgI/AAAAAAAAAGk/hN14beGHwjs/s1600/results.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;
Here is the code I used to get to the information. It scrapes all the links provided in the popular section for each letter and writes a dump of all entries. The dumps can later be used to study the data.&lt;/p&gt;
&lt;pre&gt;
&lt;span class="PreProc"&gt;require&lt;/span&gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;rubygems&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;
&lt;span class="PreProc"&gt;require&lt;/span&gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;hpricot&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;
&lt;span class="PreProc"&gt;require&lt;/span&gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;open-uri&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;
&lt;span class="PreProc"&gt;require&lt;/span&gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;entry&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;
&lt;span class="PreProc"&gt;require&lt;/span&gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;net/http&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;
&lt;span class="PreProc"&gt;require&lt;/span&gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;json&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;

&lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;retrieve_votes&lt;/span&gt;(doc)
  &lt;span class="Comment"&gt;# in-browser, votes are retrieved through an ajax call after the web page is loaded&lt;/span&gt;
  (doc/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;td.tools&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;tools&lt;/span&gt;|
    id = tools[&lt;span class="Constant"&gt;:id&lt;/span&gt;]
    uncacheable_id = id.scan(&lt;span class="Special"&gt;/&lt;/span&gt;&lt;span class="Special"&gt;\d&lt;/span&gt;&lt;span class="Special"&gt;+&lt;/span&gt;&lt;span class="Special"&gt;/&lt;/span&gt;)[&lt;span class="Constant"&gt;0&lt;/span&gt;]

    json_response = &lt;span class="Type"&gt;Net&lt;/span&gt;::&lt;span class="Type"&gt;HTTP&lt;/span&gt;.post_form(&lt;span class="Type"&gt;URI&lt;/span&gt;.parse(&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;&lt;a href="http://www.urbandictionary.com/uncacheable.php"&gt;http://www.urbandictionary.com/uncacheable.php&lt;/a&gt;&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;), {&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;ids&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;=&amp;gt; uncacheable_id})
    thumbs = &lt;span class="Type"&gt;JSON&lt;/span&gt;.parse(json_response.body)[&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;thumbs&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;][&lt;span class="Constant"&gt;0&lt;/span&gt;]
    &lt;span class="Statement"&gt;return&lt;/span&gt; [thumbs[&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;thumbs_up&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;], thumbs[&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;thumbs_down&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;]]
  &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="PreProc"&gt;end&lt;/span&gt;

&lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;retrieve_links&lt;/span&gt; letter
  anchors = []

  doc = Hpricot(open(letter))
  (doc/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;table#columnist//tr&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;row&lt;/span&gt;|
    (row/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;td&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;cell&lt;/span&gt;|
      (cell/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;ul&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;li&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;li&lt;/span&gt;|
        (li/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;a&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;anchor&lt;/span&gt;|
          anchors &amp;lt;&amp;lt;  anchor.get_attribute(&lt;span class="Constant"&gt;:href&lt;/span&gt;)
        &lt;span class="Statement"&gt;end&lt;/span&gt;
      &lt;span class="Statement"&gt;end&lt;/span&gt;
    &lt;span class="Statement"&gt;end&lt;/span&gt;
  &lt;span class="Statement"&gt;end&lt;/span&gt;

  anchors
&lt;span class="PreProc"&gt;end&lt;/span&gt;

&lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;build_entry&lt;/span&gt;(doc)
    word = &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;no words found&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
    definition = &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;no definitions found&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;

    up, down = retrieve_votes(doc)
    (doc/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;td.word&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;wrd&lt;/span&gt;|
      word = wrd.to_plain_text
      &lt;span class="Statement"&gt;break&lt;/span&gt;
    &lt;span class="Statement"&gt;end&lt;/span&gt;
    (doc/&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;div.definition&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;).each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;defined&lt;/span&gt;|
      definition = defined.to_plain_text
      &lt;span class="Statement"&gt;break&lt;/span&gt;
    &lt;span class="Statement"&gt;end&lt;/span&gt;

    &lt;span class="Type"&gt;Entry&lt;/span&gt;.new(word, definition, up, down)
&lt;span class="PreProc"&gt;end&lt;/span&gt;

&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZ&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;.each_char &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;letter&lt;/span&gt;|
  links = retrieve_links(&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;&lt;a href="http://www.urbandictionary.com/popular.php?character="&gt;http://www.urbandictionary.com/popular.php?character=&lt;/a&gt;&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;letter&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;)
  entries = []
  links.each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;link&lt;/span&gt;|
    sleep &lt;span class="Constant"&gt;5&lt;/span&gt;
    puts &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;fetching &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;link&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
    doc = Hpricot(open(&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;&lt;a href="http://www.urbandictionary.com"&gt;http://www.urbandictionary.com&lt;/a&gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt; + link))
    entries &amp;lt;&amp;lt; build_entry(doc)
  &lt;span class="Statement"&gt;end&lt;/span&gt;

  &lt;span class="Type"&gt;File&lt;/span&gt;.open(&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;letter&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;letter&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Constant"&gt;.dump&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;,&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;w&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;){|&lt;span class="Identifier"&gt;file&lt;/span&gt;|
    file.write(&lt;span class="Type"&gt;Marshal&lt;/span&gt;.dump(entries))
  }
&lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The Entry class is defined like so.&lt;/p&gt;
&lt;pre&gt;
&lt;span class="PreProc"&gt;class&lt;/span&gt; &lt;span class="Type"&gt;Entry&lt;/span&gt;
  &lt;span class="Statement"&gt;attr_accessor&lt;/span&gt; &lt;span class="Constant"&gt;:word&lt;/span&gt;, &lt;span class="Constant"&gt;:definition&lt;/span&gt;, &lt;span class="Constant"&gt;:up&lt;/span&gt;, &lt;span class="Constant"&gt;:down&lt;/span&gt;
  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;initialize&lt;/span&gt; word, definition, up, down
    &lt;span class="Identifier"&gt;@word&lt;/span&gt; = word
    &lt;span class="Identifier"&gt;@definition&lt;/span&gt; = definition
    &lt;span class="Identifier"&gt;@up&lt;/span&gt; = up
    &lt;span class="Identifier"&gt;@down&lt;/span&gt; = down
  &lt;span class="PreProc"&gt;end&lt;/span&gt;

  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;&amp;lt;=&amp;gt;&lt;/span&gt;(other)
    (other.up - other.down) - (&lt;span class="Identifier"&gt;@up&lt;/span&gt; - &lt;span class="Identifier"&gt;@down&lt;/span&gt;)
  &lt;span class="PreProc"&gt;end&lt;/span&gt;

  &lt;span class="PreProc"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;to_s&lt;/span&gt;
    &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;word&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Constant"&gt; (&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;up&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Constant"&gt; up, &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;down&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Constant"&gt; down): &lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;definition&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;span class="PreProc"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In order to get some kind of greatest hits, I used the following script. I had to filter out entries with too many down votes to get rid of the most childish entries.&lt;/p&gt;
&lt;pre&gt;
&lt;span class="PreProc"&gt;require&lt;/span&gt; &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;entry&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;

entries = []
&lt;span class="Type"&gt;Dir&lt;/span&gt;[&lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;letter*.dump&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;].sort.each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;filename&lt;/span&gt;|
  entries.concat(&lt;span class="Type"&gt;Marshal&lt;/span&gt;.load(&lt;span class="Type"&gt;File&lt;/span&gt;::open(filename).read))
&lt;span class="Statement"&gt;end&lt;/span&gt;

entries.sort!
entries.reject! {|&lt;span class="Identifier"&gt;entry&lt;/span&gt;| entry.down &amp;gt; &lt;span class="Constant"&gt;1000&lt;/span&gt;}
html=&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="Constant"&gt;50&lt;/span&gt;.times &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;i&lt;/span&gt;|
  i = i + &lt;span class="Constant"&gt;1&lt;/span&gt;
  html += &lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;i&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td style='padding: 0 2em 0 2em;'&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;entries[i].word&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;a href=\&amp;quot;&lt;a href="http://www.urbandictionary.com/define.php?term="&gt;http://www.urbandictionary.com/define.php?term=&lt;/a&gt;&lt;/span&gt;&lt;span class="Special"&gt;#{&lt;/span&gt;entries[i].word&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Constant"&gt;\&amp;quot;&amp;gt;read more&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="Statement"&gt;end&lt;/span&gt;
html+=&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;&amp;quot;&lt;/span&gt;

puts html
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-2919971192753929808?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/2919971192753929808/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=2919971192753929808" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/2919971192753929808?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/2919971192753929808?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2009/12/urban-dictionarys-greatest-hits.html" title="urban dictionary's greatest hits" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_c-z10zbSfTE/SxctePmVmgI/AAAAAAAAAGk/hN14beGHwjs/s72-c/results.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUAHQn84fCp7ImA9WxNaFUg.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-7674100625661024960</id><published>2009-11-29T23:08:00.001-06:00</published><updated>2009-11-29T23:08:53.134-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-29T23:08:53.134-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="pairing" /><title>pair programming prep</title><content type="html">What can we do &lt;b&gt;before&lt;/b&gt; pairing to make it more effective?&lt;ul&gt;&lt;li&gt;Make sure both peers focus on productivity to get the ego and flowery phrases out of the way&lt;/li&gt;&lt;li&gt;Agree on a game plan. What problem are we solving? What type of pairing is this going to be? (ball and board or coder/navigator or ping pong)&lt;/li&gt;&lt;li&gt;Understand the benefits/costs of pairing&lt;/li&gt;&lt;li&gt;Negotiation: Roy Miller of RoleModel Software offers a suggestion: &lt;blockquote&gt;One of the best tricks I've ever used when pairing is to start each pairing session with some 'negotiation.' I lay out what I like and don't like when I pair with someone, things I do well and things I don't do well, things I need help on, things that bug me to death. Then I listen while the other person does the same. This takes less than five minutes, usually, but the results are staggering. Both members of the pair then can use the pairing session as a time to get work done and to help the other person. I think 'pairing as negotiation' is a key concept.&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Read more: &lt;a href="http://safari.informit.com/0201745763"&gt;Pair Programming Illuminated&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-7674100625661024960?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/7674100625661024960/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=7674100625661024960" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/7674100625661024960?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/7674100625661024960?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2009/11/pair-programming-prep.html" title="pair programming prep" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;DE4HQH0yeyp7ImA9WxVWGE4.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-6114830518544141304</id><published>2009-02-28T10:02:00.000-06:00</published><updated>2009-02-28T10:02:11.393-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-28T10:02:11.393-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="social actions" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="change the web" /><title>change the web challenge</title><content type="html">&lt;p&gt;
The not-for-profit &lt;a href="http://www.socialactions.com/"&gt;Social Actions&lt;/a&gt; just launched the &lt;a href="http://www.socialactions.com/changetheweb"&gt;Change the Web Challenge&lt;/a&gt;. The idea is to come up with the greatest application you can think of that leverages their API.
&lt;/p&gt;
&lt;p&gt;
Their API allows you to search a database of social actions -- things like volunteering opportunities, fundraising events, petitions -- aggregated from contributors like &lt;a href="http://kiva.org"&gt;kiva.org&lt;/a&gt; or &lt;a href="http://idealist.org"&gt;idealist.org&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
For a quick peek at what you have access to, you can try my very own &lt;a href="http://www.quicksandboxer.com/socialactions"&gt;search for opportunities&lt;/a&gt;. The code for it is available as a &lt;a href="http://github.com/matstc/search-for-opportunities/tree"&gt;git repository&lt;/a&gt;.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-6114830518544141304?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/6114830518544141304/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=6114830518544141304" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6114830518544141304?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6114830518544141304?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2009/02/change-web-challenge.html" title="change the web challenge" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CE8DQXY6eSp7ImA9WxRbEEo.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-6815885852009202592</id><published>2008-11-30T12:20:00.000-06:00</published><updated>2008-11-30T13:21:10.811-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-30T13:21:10.811-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="test" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>test-first VS writing a test harness</title><content type="html">&lt;p&gt;There is a common understanding that code written using a test-first approach (as in TDD-style) ends up being more maintainable than code that has been harnessed with tests later on. I would justify that understanding as follows:
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;TDD simplifies original design&lt;/b&gt;. This one is easy. By driving the design through small unit tests, we never write code that is unnecessary and experienced TDDers know to make the tests pass with the simplest thing that works. Further, because we gain immediately from writing testable code, the code usually ends up loosely coupled with no implicit dependencies and few explicit dependencies.&lt;br/&gt;
Another thing is that by writing the code that exercises the implementation, we design both sides of the API, client code and implementation at the same time. I blogged about &lt;a href="http://clipboarded.blogspot.com/2008/07/ideal-client-code-as-design.html"&gt;client code as design&lt;/a&gt; some time ago.
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;The tests once failed for lack of functionality&lt;/b&gt;. To make sure the test is bug-free -- and actually testing the upcoming functionality -- it is imperative to make it fail before making it pass. If you're testing first, that's easy. If you're writing a test harness, you might have to comment out a bit of code to get the red bar, but then will it still compile? Will it still be coherent at runtime? A test harness is forever dubious.
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;TDD gives you fine-grained coverage&lt;/b&gt;. With very little overhead, TDD gives you fine-grained coverage since you're writing the simplest test that brings you forward, all the time. In the words of &lt;a href="http://www.amazon.com/xUnit-Test-Patterns-Refactoring-Addison-Wesley/dp/0131495054/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1228071465&amp;sr=8-1"&gt;Gerard Meszaros&lt;/a&gt;, this gives you better &lt;i&gt;Defect Localization&lt;/i&gt;. When writing a test harness, we usually emphasize the higher level functionality and forget about the smaller 'units' of work. These smaller units might be hard to test because they are implicit, hidden/encapsulated, or even unfathomable.
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Test/Specification mismatch&lt;/b&gt;. The tests are the requirements for the code. The BDD people have taken this to the next level, but it remains true with TDD. Test code is the most useful documentation to a fellow developer: it's working, up to date, terse, and it serves as an example of client code.
When developing TDD-style, the tests become the developers' understanding of the stories -- the ultimate reference.&lt;br/&gt;
If writing tests later on, we need to match the functional requirements with the actual codebase, like pieces of a puzzle. Except there will be mismatches, where the developers were not really clear about the requirements. What are we to do then? For this reason alone, test harnessing a big codebase is just really, &lt;i&gt;really&lt;/i&gt; hard.
&lt;/p&gt;

Interestingly, most of the benefits derived from test-first development are gone even if you write the tests right after new code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-6815885852009202592?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/6815885852009202592/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=6815885852009202592" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6815885852009202592?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6815885852009202592?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2008/11/test-first-vs-writing-test-harness.html" title="test-first VS writing a test harness" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;CUANQX4-fCp7ImA9WxRWEEk.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-6787836232150397551</id><published>2008-10-26T12:53:00.000-05:00</published><updated>2008-10-26T12:56:30.054-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-26T12:56:30.054-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="free culture" /><category scheme="http://www.blogger.com/atom/ns#" term="book" /><title>about free culture</title><content type="html">&lt;p&gt;I just finished reading The &lt;a href="http://www.the-future-of-ideas.com/"&gt;Future Of Ideas&lt;/a&gt; and &lt;a href="http://www.free-culture.cc/"&gt;Free Culture&lt;/a&gt;. I read both books avidly and I would recommend them to pretty much anyone -- programmer or not. What's more, they are both available for free online, under a creative commons license.
&lt;/p&gt;
&lt;p&gt;In both books, &lt;a href="http://lessig.org"&gt;Lessig&lt;/a&gt; dissects the state and the fate of the commons in american society. The commons are to be cherished and cared for as they lead to innovation, creativity, and a free culture.
&lt;/p&gt;
&lt;p&gt;The Future Of Ideas is mostly concerned about explaining the concept of commons and the one of layers. The idea of layers is taken from &lt;a href="http://en.wikipedia.org/wiki/Yochai_Benkler"&gt;Yochai Benkler&lt;/a&gt; and divides the network in three parts: the physical layer, the code, and the content. Lessig then explains how the balance of control at each layer affects innovation and creativity. The example stories include Napster, MP3.com, UNIX, and deCSS.
&lt;/p&gt;
&lt;p&gt;Free Culture is mostly concerned about the effects of excessive control on culture. Lessig discusses copyright law, intellectual property, and the concentration of the media. The example stories include the infamous RIAA lawsuits and the &lt;a href="http://en.wikipedia.org/wiki/Eldred_v._Ashcroft"&gt;Eldred v. Ashcroft&lt;/a&gt; case.
&lt;/p&gt;
&lt;p&gt;A few things strike me about this free culture debate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is no clear stakeholder in the 'new'. The new innovators and creators that free culture helps aren't yet established. This makes the fight incredibly hard to win. It's another case of special interests violating the people.&lt;/li&gt;
&lt;li&gt;There is no obvious way to disagree with Lessig unless you have a stake in the 'old'. Lessig explains his case rationally and is smart enough to include the whole political spectrum with his arguments.&lt;/li&gt;
&lt;li&gt;Prolonging the term of existing copyrights is absurd. The objective of copyrights is to give an incentive to innovators. Once the innovation has seen the light of day, prolonging the term of copyrights delays their introduction in the public domain where they could give rise to even more innovation. Thus, prolonging the term of copyrights goes against their prime objective.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a side note, another book from Lessig just came out: &lt;a href="http://remix.lessig.org/"&gt;Remix&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-6787836232150397551?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/6787836232150397551/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=6787836232150397551" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6787836232150397551?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/6787836232150397551?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2008/10/about-free-culture.html" title="about free culture" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C04GQnwyeyp7ImA9WxRXGUs.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-8552901317582491526</id><published>2008-09-15T11:58:00.002-05:00</published><updated>2008-10-25T14:12:03.293-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-25T14:12:03.293-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rake" /><title>skip dependencies in Rake</title><content type="html">&lt;p&gt;Here is a handy rake task to skip dependencies whenever you want to:&lt;/p&gt;

&lt;pre&gt;
desc &lt;span class="Special"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;Skip dependencies of subsequent tasks&lt;/span&gt;&lt;span class="Special"&gt;'&lt;/span&gt;
task &lt;span class="Constant"&gt;:skip&lt;/span&gt; &lt;span class="Statement"&gt;do&lt;/span&gt;
  &lt;span class="Type"&gt;Rake&lt;/span&gt;::&lt;span class="Type"&gt;Task&lt;/span&gt;.tasks.each &lt;span class="Statement"&gt;do&lt;/span&gt; |&lt;span class="Identifier"&gt;t&lt;/span&gt;|
    t.clear_prerequisites
  &lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;span class="Statement"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-8552901317582491526?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/8552901317582491526/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=8552901317582491526" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/8552901317582491526?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/8552901317582491526?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2008/09/skip-dependencies-in-rake.html" title="skip dependencies in Rake" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEAHSXk6fCp7ImA9WxRSFEw.&quot;"><id>tag:blogger.com,1999:blog-3313530259099615004.post-598773929337347691</id><published>2008-09-14T13:13:00.005-05:00</published><updated>2008-09-14T13:25:38.714-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-14T13:25:38.714-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="pyweek" /><category scheme="http://www.blogger.com/atom/ns#" term="game" /><title>pyweek 7 is over</title><content type="html">&lt;a href="http://www.pyweek.org/"&gt;PyWeek&lt;/a&gt; just went by. A python programming challenge where participants have one week to make a game.
&lt;br/&gt;&lt;br /&gt;
Here is our project page: &lt;a href="http://code.google.com/p/strlen/"&gt;google code strlen&lt;/a&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;
Or you can check it out like so:
&lt;br /&gt;
&lt;div class="code"&gt;svn checkout http://strlen.googlecode.com/svn/trunk/ strlen&lt;/div&gt;
&lt;br /&gt;
&lt;img border="0" src="http://2.bp.blogspot.com/_c-z10zbSfTE/SM1V2yW7kvI/AAAAAAAAADE/Xl9gOtSwo94/s320-R/screenshot-strlen.png" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3313530259099615004-598773929337347691?l=clipboarded.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://clipboarded.blogspot.com/feeds/598773929337347691/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3313530259099615004&amp;postID=598773929337347691" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/598773929337347691?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3313530259099615004/posts/default/598773929337347691?v=2" /><link rel="alternate" type="text/html" href="http://clipboarded.blogspot.com/2008/09/pyweek-7-is-over.html" title="pyweek 7 is over" /><author><name>mats</name><uri>http://www.blogger.com/profile/09415156435863824246</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_c-z10zbSfTE/SM1V2yW7kvI/AAAAAAAAADE/Xl9gOtSwo94/s72-Rc/screenshot-strlen.png" height="72" width="72" /><thr:total>0</thr:total></entry></feed>

