<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-165807313160822069</id><updated>2026-09-20T06:59:32.809-04:00</updated><category term="programming"/><category term="linux"/><category term="computers"/><category term="ruby"/><category term="economics"/><category term="personal"/><category term="statistics"/><category term="c++"/><category term="javascript"/><category term="games"/><category term="jruby"/><category term="fractal"/><category term="math"/><category term="rails"/><category term="comp sci"/><category term="scala"/><category term="vim"/><category term="other"/><category term="SfPs"/><category term="c#"/><category term="open source"/><category term="python"/><category term="ironruby"/><category term="politics"/><category term="art"/><category term="learning"/><category term="php"/><category term="finance"/><category term="game-programming"/><category term="latex"/><category term="lua"/><category term="objective c"/><category term="ui"/><title type='text'>Ubuntu: A Love/Hate Relationship</title><subtitle type='html'>A spillage of thought about Ubuntu, programming, economics, and computers in general.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>349</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-9104047325161699491</id><published>2013-04-16T12:15:00.000-04:00</published><updated>2013-05-18T11:22:02.798-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="other"/><title type='text'>Distributed Coding at sweetiQ</title><content type='html'>It&#39;s been a long time since I really wrote anything on this blog, so it is time for a little update.&lt;br/&gt;&lt;br/&gt;Just over a year ago I joined another startup called &lt;a href=&quot;http://www.sweetiq.com/&quot;&gt;sweetiQ&lt;/a&gt;. It&#39;s a step up from the other startups that I&#39;ve worked for in that it has actually gone live and it is actually making money. It&#39;s also interesting because this is the longest amount of time I&#39;ve spent working for a single company.&lt;br/&gt;&lt;br/&gt;The system uses &lt;a href=&quot;http://www.rabbitmq.com/&quot;&gt;RabbitMQ&lt;/a&gt; for driving a distributed computing cluster that essentially implements &lt;a href=&quot;http://en.wikipedia.org/wiki/Actor_model&quot;&gt;Actor model&lt;/a&gt; of computation, except rather than working with threads within a single machine we&#39;re using multiple processes on multiple machines (100+). Each process has a set of endpoints that listen on different queues, RabbitMQ manages dispatching these messages to the different worker nodes.&lt;br/&gt;&lt;br/&gt;One of my major contributions is what I&#39;m calling a &quot;distributed job control system.&quot; There are many steps in each &quot;job&quot; that the system must do, and each step of the job may be handled by a different process across different machines. As a particular computing job becomes more complex, several problems arise:&lt;br/&gt;&lt;ul&gt;&lt;br/&gt;	&lt;li&gt;managing the dependency structure between various components of each job. In a simple sequential system you can do A, then B, then C; the dependency structure is very simple: if x depends on y, do y after x. In a distributed system B may not depend on A, so you can do them in parallel, but C depends on the output of both A and B so the system cannot start C until both A and B are done. It is not possible to just have the node handling C wait for a response of both A and B, because the messages from A and B may not be delivered to the same node that can handle C. Even more complex, in certain cases C may not need the computation from A but in other times it does - for example if we&#39;re aggregating social data from different networks but the user hasn&#39;t linked their Twitter account, we don&#39;t need to fetch data from Twitter.&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;the possibility of failure increases - sometimes a node will lose its database connection. Sometimes a node will die (exmaple: we use Amazon spot instances that at any time can just shut down). Sometimes a node that attempts to fetch something on the Internet may fail for whatever reason (the API version of Twitter&#39;s fail whale is something that has happened relatively frequently). In this case the process needs some sort of elegant failure handling - often the solution is just to try again later. Other times we need to send a message to the user informing them that they need to take some sort of action (if a user changes their Facebook password, it will invalidate the stored OAuth token).&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;need to rate-limit certain jobs - some jobs can have many sub-components done in parallel, we have encountered some problems sending out too many messages in parallel. The first and most obvious problem that we hit is that the database will choke, however once we learned how to use MongoDB properly this became a non-issue (having scaled both MySQL databases and MongoDB databases, I can tell you I am fully sold on MongoDB at this point). The bigger issue was a problem of process starvation: at peak times jobs will begin spawning at an enormous rate, and if we keep sending parallel messages for stage 1, the computation nodes spend most their time processing messages for stage 1 (Rabbit has no concept of priority). There is a need for the control system to detect starvation and alleviate it (a variety of different ways we can do this).&lt;/li&gt;&lt;br/&gt;	&lt;li&gt;recursive job types - our data is hierarchical. A user can categorize components of what they &quot;own&quot; in groups and sub-groups, and may want to be able to break down aggregated information at each level. Each job may need to perform itself separately on a child node, which may in turn need to perform itself on its own children, etc. Having some sort of way to easily specify recursive sub-jobs saves a ton of time.&lt;/li&gt;&lt;br/&gt;&lt;/ul&gt;&lt;br/&gt;What I ended up building is a system that takes a high-level description of a distributed job and controls that job across the different nodes. Rather than having each endpoint communicate directly with one another, they communicate with the central controller that tracks their progress and makes decisions on what control points to activate. The huge benefit of this is that it is a separation of concerns: the endpoints can focus on doing their particular computation well, while the &quot;bigger picture&quot; concerns like starvation and node failure can be handled by the control system.&lt;br/&gt;The system can handle recursive job structures and in fact it can handle any type of sub-job: any job can trigger any other job as a child, including itself. This makes it trivially easy to run one component of a job so that you don&#39;t need to go through everything in order to do what needs to be done. It also allows you to remain DRY: you can abstract out certain commonly-used components and use them as a &quot;library&quot; of sorts to compose more complex jobs.&lt;br/&gt;&lt;br/&gt;The code is not currently available, however we are trying to figure out the legal implications of open-sourcing the software. Ideally we&#39;ll figure all this out in the near future, and I&#39;ll be happy to release it for everyone to play with.&lt;br/&gt;&lt;br/&gt;Shameless company promotion: If this type of work interests you, send me a message. Like most dev shops, we&#39;re always happy to bring in smart folks.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/9104047325161699491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/9104047325161699491' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/9104047325161699491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/9104047325161699491'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2013/04/distributed-coding-at-sweetiq.html' title='Distributed Coding at sweetiQ'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-1574730391409826941</id><published>2013-02-21T11:59:00.000-05:00</published><updated>2013-05-18T11:22:02.793-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="other"/><title type='text'>Typing as seen by Fanboys</title><content type='html'>Thought this was kind of funny:&lt;br/&gt;&lt;br/&gt;&lt;img src=&quot;http://www.robbritton.com/wp-content/uploads/languages.png&quot; alt=&quot;&quot; /&gt;</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/1574730391409826941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/1574730391409826941' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1574730391409826941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1574730391409826941'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2013/02/typing-as-seen-by-fanboys.html' title='Typing as seen by Fanboys'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-160783442415166256</id><published>2012-02-27T10:40:00.000-05:00</published><updated>2013-05-18T11:22:02.783-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="vim"/><title type='text'>Vim Relative Line Numbers</title><content type='html'>A little trick I learned the other day at &lt;a href = &quot;http://www.montrealonrails.com/&quot;&gt;Montreal.rb&lt;/a&gt;: relative-line numbering (can be enabled with &lt;code&gt;:set rnu&lt;/code&gt;). The current line number is zero, and the left-hand column shows the distance from your cursor. This way you can easily do commands like &lt;code&gt;d5k&lt;/code&gt; to delete the 5 lines above the cursor, or &lt;code&gt;d5j&lt;/code&gt; to delete the 5 lines below it.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/160783442415166256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/160783442415166256' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/160783442415166256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/160783442415166256'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2012/02/vim-relative-line-numbers.html' title='Vim Relative Line Numbers'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-8065521092911156509</id><published>2012-02-24T12:42:00.000-05:00</published><updated>2013-05-18T11:22:02.788-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c#"/><category scheme="http://www.blogger.com/atom/ns#" term="programming"/><title type='text'>Asynchronous Function Looping in C#</title><content type='html'>It is often the case in code that you have to do several things in a sequence since each computation is dependent on the one(s) before it:&lt;pre&gt;// ...&lt;br/&gt;// stuff 1&lt;br/&gt;// ...&lt;br/&gt;// stuff 2&lt;br/&gt;// ...&lt;br/&gt;// stuff 3&lt;br/&gt;// ... etc.&lt;/pre&gt;Good software techniques will tell you that you should break some of these up into methods:&lt;pre&gt;&lt;br/&gt;stuff1();&lt;br/&gt;stuff2();&lt;br/&gt;stuff3();&lt;/pre&gt;If it gets big, you can even put it all in a collection and iterate (we&#39;re starting to get into weird coding now, I don&#39;t think anybody would actually do this):&lt;pre&gt;var collection = new List&amp;lt;Action&amp;gt;() { stuff1, stuff2, stuff3 };&lt;br/&gt;foreach (var func in collection){&lt;br/&gt;  func();&lt;br/&gt;}&lt;/pre&gt;Now the part where this would actually be useful. What if some of these functions could potentially be asynchronous? That is, they depend on some value that may not be readily available - maybe user input, maybe some data from a network, etc. Blocking is not usually a great option - a modal dialog demands that the user pays attention to it even if there is something more important somewhere else. It would be better if this computation could &quot;pause&quot; and then resume later on when we get what we need. In some languages including Scheme and Ruby, you can accomplish this using a construct called &lt;code&gt;callcc&lt;/code&gt;:&lt;pre&gt;var collection = new List&amp;lt;Action&amp;lt;Action&amp;gt;&amp;gt;() { stuff1, stuff2,&lt;br/&gt;                                              stuff3 };&lt;br/&gt;foreach (var func in collection){&lt;br/&gt;  // pseudo-code warning&lt;br/&gt;  call_cc(func);&lt;br/&gt;}&lt;/pre&gt;Here, &lt;code&gt;call_cc()&lt;/code&gt; will call &lt;code&gt;func&lt;/code&gt; and pass in a function which will start executing right after the &lt;code&gt;call_cc()&lt;/code&gt; call: it is a &lt;i&gt;continuation&lt;/i&gt; of the loop. When &lt;code&gt;func&lt;/code&gt; is done (or when it receives the response it wants), it can call this function to nicely continue executing the loop.&lt;br/&gt;&lt;br/&gt;Unfortunately, C# 4.0 and lower do not support anything like &lt;code&gt;callcc&lt;/code&gt;. C# 5.0 will support the &lt;code&gt;await&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt; keywords which will accomplish exactly what we want, but for the time being we&#39;ll have to make do with what we have. How can we do that without &lt;code&gt;callcc&lt;/code&gt;?&lt;br/&gt;&lt;br/&gt;Let&#39;s give it a shot using a recursive function:&lt;pre&gt;void AsyncForeach(IEnumerator&amp;lt;Action&amp;lt;Action&amp;gt;&amp;gt; iter){&lt;br/&gt;  if (iter.MoveNext()){&lt;br/&gt;    iter.Current( () =&gt; {&lt;br/&gt;      AsyncForeach(iter);&lt;br/&gt;    });&lt;br/&gt;  }&lt;br/&gt;}&lt;br/&gt;void OtherFunc(){&lt;br/&gt;  // ...&lt;br/&gt;  var collection = new List&amp;lt;Action&amp;lt;Action&amp;gt;&amp;gt;() { stuff1, stuff2,&lt;br/&gt;                                                stuff3 };&lt;br/&gt;  &lt;br/&gt;  AsyncForeach(collection.GetEnumerator());&lt;br/&gt;}&lt;/pre&gt;This would require every function in &lt;code&gt;collection&lt;/code&gt; adhere to the &lt;code&gt;Action&amp;lt;Action&amp;gt;&lt;/code&gt; delegate and when it is done, it will need to call the continuation manually in order to resume the computation. This is a bit annoying, and it&#39;s why all the &lt;code&gt;BeginConnect&lt;/code&gt;, &lt;code&gt;BeginSend&lt;/code&gt;, etc. in &lt;code&gt;System.Net&lt;/code&gt; require an &lt;code&gt;AsyncCallback&lt;/code&gt; to call when they are done. The new &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; keywords will be extremely useful to accomplish our task since everything is called automatically:&lt;pre&gt;var collection = new List&amp;lt;Action&amp;gt;() { stuff1, stuff2, stuff3 };&lt;br/&gt;foreach (var func in collection){&lt;br/&gt;  // func doesn&#39;t even need to call anything to&lt;br/&gt;  // keep this thing going!&lt;br/&gt;  await func();&lt;br/&gt;}&lt;/pre&gt;It is useful to learn this from approach though. Say we want to halt the loop prematurely from within one of the functions. In that case, the function could simply not call the continuation. That would end our recursion, causing us to break out of our loop - the equivalent of the &lt;code&gt;break&lt;/code&gt; keyword. In order to do that with the &lt;code&gt;await&lt;/code&gt; keyword we&#39;d have to have some sort of exception handling system, or return type, etc.&lt;br/&gt;&lt;br/&gt;We could go even further and implement something similar to Python&#39;s &lt;code&gt;for...else&lt;/code&gt; construct where if &lt;code&gt;break&lt;/code&gt; is called somewhere in the computation it will run the &lt;code&gt;else&lt;/code&gt; block:&lt;pre&gt;for i in range(10):&lt;br/&gt;  if i == 5:&lt;br/&gt;    break&lt;br/&gt;else:&lt;br/&gt;  # this is executed&lt;br/&gt;  print &quot;should run&quot;&lt;br/&gt;&lt;br/&gt;for i in range(10):&lt;br/&gt;  if i == 12:&lt;br/&gt;    break&lt;br/&gt;else:&lt;br/&gt;  # this is not executed&lt;br/&gt;  print &quot;should not run&quot;&lt;/pre&gt;We can do this by adding failure &quot;continuations&quot; to our functions:&lt;pre&gt;void AsyncForeach(IEnumerator&amp;lt;Action&amp;lt;Action, Action&amp;gt;&amp;gt; iter,&lt;br/&gt;                  Action failure){&lt;br/&gt;  if (iter.MoveNext()){&lt;br/&gt;    iter.Current( () =&gt; {&lt;br/&gt;      AsyncForeach(iter, failure);&lt;br/&gt;    }, failure);&lt;br/&gt;  }&lt;br/&gt;}&lt;br/&gt;void OtherFunc(){&lt;br/&gt;  // ...&lt;br/&gt;  var collection =&lt;br/&gt;    new List&amp;lt;Action&amp;lt;Action, Action&amp;gt;&amp;gt;() { stuff1, stuff2, stuff3 };&lt;br/&gt;  &lt;br/&gt;  AsyncForeach(collection.GetEnumerator(), () =&gt; {&lt;br/&gt;    // handle failure&lt;br/&gt;  });&lt;br/&gt;}&lt;/pre&gt;In this case the functions &lt;code&gt;stuff1&lt;/code&gt;, &lt;code&gt;stuff2&lt;/code&gt;, etc. will call the first function if they should continue looping, or call the second one in case of failure.&lt;br/&gt;&lt;br/&gt;There&#39;s one final tweak to all of this. At the moment there are two problems with &lt;code&gt;AsyncForeach&lt;/code&gt;: it depends on the type of the list we&#39;re iterating over (&lt;code&gt;IEnumerator&amp;lt;Action&amp;lt;Action, Action&amp;gt;&amp;gt;&lt;/code&gt;), and it does not close over any variables that we may need for the loop. Can we do this using a closure?&lt;br/&gt;&lt;br/&gt;In fact, we can:&lt;pre&gt;var collection =&lt;br/&gt;    new List&amp;lt;Action&amp;lt;Action, Action&amp;gt;&amp;gt;() { stuff1, stuff2, stuff3 };&lt;br/&gt;&lt;br/&gt;// declare looper early so that it closes over itself&lt;br/&gt;Action looper = null;&lt;br/&gt;var iter = collection.GetEnumerator();&lt;br/&gt;looper = () =&gt; {&lt;br/&gt;  if (iter.MoveNext()){&lt;br/&gt;    iter.Current(looper, () =&gt; {&lt;br/&gt;      // handle failure&lt;br/&gt;    });&lt;br/&gt;  }&lt;br/&gt;};&lt;br/&gt;// don&#39;t forget to start the loop&lt;br/&gt;looper();&lt;/pre&gt;Since this isn&#39;t so DRY, we can top it all off with a function that returns a function:&lt;pre&gt;Action GetAsyncForeach&amp;lt;T&amp;gt;(IEnumerable&amp;lt;T&amp;gt; collection,&lt;br/&gt;                          Action&amp;lt;T&amp;gt; body){&lt;br/&gt;  var iter = collection.GetEnumerator();&lt;br/&gt;  return () =&gt; {&lt;br/&gt;    if (iter.MoveNext()){&lt;br/&gt;      body(iter.Current);&lt;br/&gt;    }&lt;br/&gt;  };&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;void OtherFunc(){&lt;br/&gt;  // ...&lt;br/&gt;  var collection =&lt;br/&gt;    new List&amp;lt;Action&amp;lt;Action, Action&amp;gt;&amp;gt;() { stuff1, stuff2, stuff3 };&lt;br/&gt;  &lt;br/&gt;  Action checker = null;&lt;br/&gt;  checker = GetAsyncForeach(collection, (current) =&gt; {&lt;br/&gt;    current(checker, () =&gt; {&lt;br/&gt;      // handle failure&lt;br/&gt;    });&lt;br/&gt;  });&lt;br/&gt;  checker(); // start the loop&lt;br/&gt;}&lt;/pre&gt;We now have a DRY, re-usable component for implementing an asynchronous foreach loop in our code. It&#39;s not the most elegant approach, but it works really well and we don&#39;t need that much extra boiler plate to get this done (if C# supported a &lt;code&gt;let rec&lt;/code&gt; keyword, we could make it even shorter!).&lt;br/&gt;&lt;br/&gt;This is a useful method of looping through some asynchronous tasks that you may have to do. I found myself needing this sort of thing when calling &lt;code&gt;ShowDialog&lt;/code&gt; would lock the entire GUI while the system waited for the user to input something, however sometimes the user would have to attend to something else before responding to the dialog. Since later actions in the loop depended on the result of the dialog box, a more asynchronous method was necessary.&lt;br/&gt;&lt;br/&gt;Ultimately, this is why I believe that all programmers should have some experience with functional programming; this is a technique that would be obvious to a programmer in Lisp or OCaml but might be a bit trickier to someone who just has OO experience. Having functional programming know-how in your toolbelt will make you a better C# programmer.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/8065521092911156509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/8065521092911156509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/8065521092911156509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/8065521092911156509'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2012/02/asynchronous-function-looping-in-c.html' title='Asynchronous Function Looping in C#'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-1775084843460134398</id><published>2012-02-12T22:15:00.000-05:00</published><updated>2013-05-18T11:22:02.768-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Non-deterministic Programming - Amb</title><content type='html'>I&#39;ve been very slowly plowing through &lt;a href = &quot;http://mitpress.mit.edu/sicp/&quot;&gt;SICP&lt;/a&gt; and I&#39;ve recently read through their chapter on &lt;a href = &quot;http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-28.html#%_sec_4.3&quot;&gt;non-deterministic programming&lt;/a&gt;. When you program this way your variables no longer have just one value, they can take on &lt;i&gt;all&lt;/i&gt; of their possible values until stated otherwise. An example:&lt;pre&gt;x = amb(1, 2, 3, 4)&lt;/pre&gt;In this case &lt;code&gt;x&lt;/code&gt; is all of 1, 2, 3, and 4. If you try to print out &lt;code&gt;x&lt;/code&gt; it will print out 1 because the act of printing it temporarily forces a value, but otherwise you can treat the variable as though it had all of those values.&lt;br/&gt;&lt;br/&gt;You can then force certain subsets of the values with assertions:&lt;pre&gt;assert x.odd?&lt;/pre&gt;In this case &lt;code&gt;x&lt;/code&gt; would become just 1 and 3. If you then added a final assertion that &lt;code&gt;x &gt; 2&lt;/code&gt; you would force a single value and &lt;code&gt;x&lt;/code&gt; would be 3. If you instead added the assertion &lt;code&gt;x &gt; 3&lt;/code&gt; then &lt;code&gt;x&lt;/code&gt; would have no values: an exception would be thrown saying that &lt;code&gt;x&lt;/code&gt; is basically &quot;impossible&quot;.&lt;br/&gt;&lt;br/&gt;This is useful when you are searching for something. Suppose you&#39;re trying to find numbers that satisfy Pythagorus&#39; theorem:&lt;pre&gt;a = amb(*1..10)&lt;br/&gt;b = amb(*1..10)&lt;br/&gt;c = amb(*1..10)&lt;br/&gt;&lt;br/&gt;assert a**2 + b**2 == c**2&lt;br/&gt;&lt;br/&gt;puts a, b, c&lt;br/&gt;next_value&lt;br/&gt;puts a, b, c&lt;/pre&gt;This code would print out 3, 4, and 5 on the first output, followed by 6, 8, and 10 on the second. The &lt;code&gt;next_value&lt;/code&gt; function would tell the &lt;code&gt;amb&lt;/code&gt; system to find another solution to the set of variables that satisfy the assertions we specified. If nothing else is found, an exception will be thrown.&lt;br/&gt;&lt;br/&gt;Even more interesting, there is a library in Ruby called &lt;a href = &quot;https://github.com/chikamichi/amb&quot;&gt;amb&lt;/a&gt; that implements this stuff. Unfortunately it doesn&#39;t work just like the above example, you can only get the either the first set of values that fit, or all of them:&lt;pre&gt;require &#39;rubygems&#39;&lt;br/&gt;require &#39;amb&#39;&lt;br/&gt;include Amb::Operator&lt;br/&gt;&lt;br/&gt;a = amb(*1..10)&lt;br/&gt;b = amb(*1..10)&lt;br/&gt;c = amb(*1..10)&lt;br/&gt;&lt;br/&gt;# calling amb with no arguments causes it&lt;br/&gt;# to backtrack until the criteria is met&lt;br/&gt;amb unless a*a + b*b == c*c&lt;br/&gt;&lt;br/&gt;# prints out the first match&lt;br/&gt;puts &quot;#{a}, #{b}, #{c}&quot;&lt;br/&gt;&lt;br/&gt;# prints out every match and then crashes&lt;br/&gt;amb&lt;br/&gt;puts &quot;#{a}, #{b}, #{c}&quot;&lt;/pre&gt;This is a pretty cool way to program, and it would be interesting to know when it might be practical to use. I tried it with a couple of problems on &lt;a href = &quot;http://projecteuler.net/&quot;&gt;Project Euler&lt;/a&gt; but unfortunately since the backtracking method that &lt;code&gt;amb&lt;/code&gt; uses isn&#39;t always the most efficient approach it would choke a bit. Perhaps if this gem gets some attention and some love, it might end up as something a bit more performant!</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/1775084843460134398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/1775084843460134398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1775084843460134398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1775084843460134398'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2012/02/non-deterministic-programming-amb.html' title='Non-deterministic Programming - Amb'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-3914987628912754632</id><published>2012-02-10T13:56:00.000-05:00</published><updated>2013-05-18T11:22:02.778-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="art"/><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="ui"/><title type='text'>The Brilliant Design of Magic Ink</title><content type='html'>I&#39;ve been plowing through Bret Victor&#39;s &lt;a href = &quot;http://worrydream.com/MagicInk/&quot;&gt;Magic Ink&lt;/a&gt; essay and I&#39;ve noticed a set of very interesting UI elements that I really enjoy and hope to add to my style of writing (it might even be worth it to add these features to Wordpress&#39; publishing code).&lt;br/&gt;&lt;br/&gt;These are:&lt;ul&gt;&lt;li&gt;Anchors at every paragraph: the essay is long. When I sent it to some of the fellow programmers at work, the first thing they did was complain about how long it was. Since you don&#39;t usually read a 50 page essay in one sitting, you need a way to bookmark not only the page you are on (useless since everything is on one page) but where you are on that page. Victor takes advantage of HTML&#39;s ability to set anchor points within a page to anchor &lt;i&gt;every&lt;/i&gt; paragraph so that when you don&#39;t really want to read anymore, you can just click on the hash next to paragraph (only visible when you mouse over the paragraph) and it will update your address bar to anchor to that paragraph. This is not exactly fancy modern technology, this entire feature just takes advantage of named anchors and the fact that when you click on one the browser doesn&#39;t reload the page. Extremely useful for long essays, yet I can&#39;t recall seeing this anywhere else.&lt;/li&gt;&lt;li&gt;Footnotes/endnotes are actually sidenotes. It&#39;s a bit annoying when you read an essay online that has footnotes/endnotes with a star or a cross or something and you have to scroll all the way to the bottom to see those notes (some posts make it easier by providing a link, but as vi users know moving your hand to the mouse is a pain). It takes effort and there is a disconnect between when you read what you are writing and navigating to wherever the note is. By putting the note on the side next to the paragraph, it is much easier to just move your eyes to look at the note rather scrolling or clicking. This comes at the cost of screen real-estate, however if you make the actual content of your essay thinner you don&#39;t lose a whole lot since there is still a flow when you&#39;re reading line-to-line.&lt;/li&gt;&lt;/ul&gt;&lt;br/&gt;&lt;br/&gt;I really like these UI tweaks because they are so incredibly simple, yet somehow are not very common practice. If ever I write something that is long and actually decent enough to slog through I hope to remember these little features to help people better read my stuff.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/3914987628912754632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/3914987628912754632' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/3914987628912754632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/3914987628912754632'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2012/02/the-brilliant-design-of-magic-ink.html' title='The Brilliant Design of Magic Ink'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-8749086327190797760</id><published>2012-01-27T15:37:00.000-05:00</published><updated>2013-05-18T11:22:02.773-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><title type='text'>Thoughts on Stanford&amp;#39;s Online Courses</title><content type='html'>Last year I enrolled in a couple of the extremely popular Stanford online classes: &lt;a href = &quot;https://www.ai-class.com/&quot;&gt;Intro to AI&lt;/a&gt; and &lt;a href = &quot;http://www.ml-class.org/&quot;&gt;Machine Learning&lt;/a&gt;. While many other people who took the courses also wrote on the topic I feel like none of the descriptions quite matched how I feel about the courses, so I think I will talk about them a little bit here.&lt;br/&gt;&lt;br/&gt;First, the good things:&lt;br/&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;The connection&lt;/b&gt; - I feel like in a course like this you have a much closer connection to the professor than you do in recorded videos like the MIT OpenCourseWare lectures or even a real classroom (with the exception of smaller class sizes) since the professor is talking directly to the camera or the camera is filming some sort of drawing surface. The professors were all extremely passionate about their topics and talked about them with so much enthusiasm (especially Sebastian Thrun) that I couldn&#39;t help but feel more enthusiastic about the topics as well - although I didn&#39;t really need the help, I found the courses very interesting! Despite the fact that in reality the video method of teaching is extremely impersonal, it seems much more personal because it is like a one-on-one enviroment where the professor is talking just to you instead of an entire classroom. Most of the time this makes you feel like you have to pay attention! Compare this to a class of 100+ students where if you fall asleep, zone out, or start doodling it&#39;s not likely the professor will notice or care.&lt;/li&gt;&lt;br/&gt;&lt;li&gt;&lt;b&gt;The flexibility&lt;/b&gt; - Picture scenario one: you&#39;re sitting in your living room in a comfy chair covered in a warm blanket sipping delicious beer. You&#39;re watching the online videos on your laptop while occasionally pausing the video to go get a snack, do some chores, or check on dinner.&lt;br/&gt;Now picture scenario two: you&#39;re sitting in a hard plastic chair in a windowless room dimly lit by the projection of PowerPoint slides onto the wall (you&#39;ve all had a class like that, don&#39;t lie) at 8am in the morning. Some guy is chewing loudly in the seat behind you while someone, somewhere is rapidly tapping their pen against the desk.&lt;br/&gt;Which enviroment would you prefer? While these are two extreme examples, personally I would prefer the former.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The technology&lt;/b&gt; - I found the websites modern and very easy to navigate with no clutter distracting you from what you were looking for. The two main hiccups that I noticed with the technology:&lt;ul&gt;&lt;li&gt;With the AI class the videos wouldn&#39;t always skip ahead to the next video or to the quiz - probably because I was watching the videos under Linux. The first time it happened it took a little while to realize that you could click on the question mark to access the quiz.&lt;/li&gt;&lt;li&gt;With the ML class the video would appear on a &quot;pop-up&quot; div inside the window and the background would fade out, but if you clicked on the background it would close the video. This was annoying when you flip to another window but then click on the browser to re-focus it and end up killing the video.&lt;/li&gt;&lt;/ul&gt;These aren&#39;t huge problems, just little bugs or UI quirks that are expected with new software. I really enjoyed the submission system for the ML class where you could submit your assignments directly from within Octave by typing &lt;code&gt;submit&lt;/code&gt;. I&#39;ve had some programming classes do this type of thing and it really makes it easy to get your work done.&lt;/li&gt;&lt;br/&gt;&lt;/ul&gt;&lt;br/&gt;&lt;br/&gt;Some things I found so-so:&lt;br/&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;The content&lt;/b&gt; - I&#39;m going to be a little harsh. The content was very interesting for both courses, however I found myself disappointed with the depth of the knowledge. It seemed like we were only scratching the surface of the topics without going into the detail or rigour that I would expect from a full university course. Then again, this is an introductory course and it has been a long time since I took an introductory course to anything. Maybe I&#39;m just biased.&lt;/li&gt;&lt;br/&gt;&lt;/ul&gt;&lt;br/&gt;&lt;br/&gt;Inevitably, the downsides:&lt;br/&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;The assignments&lt;/b&gt; - I&#39;m a person that learns by doing. I can see the things in the lecture and understand them fully, but everything tends to go in one ear and right out the other. When it comes to applying the concepts learned in the lecture I need to do it myself before the material really sinks in. In the AI class I found that the only assignment/quiz that I really connected with was the optional assignment for a simple decryption problem using NLP and statistics that was presented at the very end of the course. The rest of the assignments were just quizzes and while you do learn something by having to answer questions, I felt that the learning wasn&#39;t quite as deep on these topics as it could have been if we were actually supposed to program something.&lt;br /&gt;With the ML class they actually did have programming assignments in addition to quizzes, however with those I found that most of the time all you really had to do was translate the equations from the ones written in the assignment description to Octave and it would work. You weren&#39;t really learning and understanding what was going on, you were essentially just copying and pasting. I feel like I would have learned a lot more if the assignments had a bit more challenge to them.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Lack of interaction&lt;/b&gt; -  Some of my favourite classes involved a good deal of interaction between the professor and/or the other members of the class (seminar or lab classes come to mind). In these types of classes the interaction component is a huge benefit to learning compared to the StackOverflow-style Q&amp;A forums that they had for the AI class. Because of the online nature of the courses, there isn&#39;t really a solution to this problem that I&#39;m aware of.&lt;/li&gt;&lt;/ul&gt;&lt;br/&gt;&lt;br/&gt;I will most certainly continue to spend free time taking these online classes, unfortunately there are too many courses that I would like to take and not enough time to take them (I had this same problem back when I was in university). One thing that would be great to see is a Khan Academy style approach where you can take the class whenever you want instead of just during the semesters that they are offered.&lt;br/&gt;&lt;br/&gt;In the very unlikely chance that any of the Stanford profs read this, thanks! I really have enjoyed the classes and will continue taking them for a long time yet.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/8749086327190797760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/8749086327190797760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/8749086327190797760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/8749086327190797760'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2012/01/thoughts-on-stanford-online-courses.html' title='Thoughts on Stanford&amp;#39;s Online Courses'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-3436028512368277875</id><published>2012-01-23T14:43:00.000-05:00</published><updated>2013-05-18T11:22:02.762-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="art"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Dynamic Pictures</title><content type='html'>At &lt;a href = &quot;http://2012.cusec.net/&quot;&gt;CUSEC 2012&lt;/a&gt; a programmer/designer by the name of &lt;a href = &quot;http://worrydream.com/&quot;&gt;Bret Victor&lt;/a&gt; gave one of the most interesting presentations at the conference (he received a standing ovation for it) on the importance of having visual connections between the code you write and what that code does.&lt;br/&gt;&lt;br/&gt;Among other things, he showed a very interesting prototype where when you modify some Javascript code it will execute the code in real-time and show you exactly what will happen when you make those changes. On top of that, it provides a number of tools for &quot;tweaking&quot; constants: click on an integer and a slider will pop up above it that will modify that integer. As you move the slider the number will change, updating the visual display at the same time. Press the &#39;.&#39; after an object and it will give you an autocomplete list, but unlike every other autocomplete system it will actually show you what will happen if you call this method. Select drawRect and you will see a little black rectangle appear. Select arc and a little black circle will appear.&lt;br/&gt;&lt;br/&gt;The demo worked amazingly well, however he admitted afterwards that they weren&#39;t based on a program that works but just some proof-of-concept demos that don&#39;t actually work outside of his presentation. That inspired me to actually attempt building some of this stuff to make it easier for people to build &quot;dynamic pictures&quot; - that is, pictures that change over time and respond to what the user might want to do. This is a non-trivial task because it not only involves processing the Javascript code live, but also determining what might be &quot;good&quot; values in each case. For example if you were to be adjusting numbers in context.lineTo() you might want to go between 0 and the width/height of the canvas, but if you were in context.arc() you would want to be adjusting angles. It would involve some kind of annotations to functions to determine what the valid ranges of values are for that argument.&lt;br/&gt;&lt;br/&gt;You can check out the basic prototype &lt;a href = &quot;/dynamicpictures&quot;&gt;here&lt;/a&gt; (warning: it is very basic at the moment) and see the code on Github &lt;a href = &quot;https://github.com/robbrit/dynamicpictures&quot;&gt;here&lt;/a&gt;. When you enter code in the right-hand panel it will execute the code and any canvas drawing done will appear in the left-hand side.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/3436028512368277875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/3436028512368277875' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/3436028512368277875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/3436028512368277875'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2012/01/dynamic-pictures.html' title='Dynamic Pictures'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-1514513733365123342</id><published>2011-12-28T18:52:00.000-05:00</published><updated>2013-05-18T11:22:02.726-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="economics"/><title type='text'>World Peak Oil</title><content type='html'>In &lt;a href = &quot;http://www.robbritton.com/2011/12/27/canadian-peak-oil/&quot;&gt;my last post&lt;/a&gt; I wrote a bit about Canadian oil production vs. our proven reserves and gave some projections on how long our reserves might last. Our government says that our oil reserves will last 200 years, however I showed that that is subject to the fragile assumption that there will be no increase in production during that time. The post further shows that over the last 30 years Canadian oil production has averaged about 2.65% growth per year, so using that as a baseline for future oil growth the length of time until Canadian reserves run dry is about 70 years.&lt;br/&gt;&lt;br/&gt;This post will blow all that out of the water and show that 70 years is much longer than a more realistic estimate.&lt;br/&gt;&lt;br/&gt;I picked up some data from the CIA World Factbook on global oil &lt;a href = &quot;https://www.cia.gov/library/publications/the-world-factbook/rankorder/2174rank.html&quot;&gt;consumption&lt;/a&gt; and &lt;a href = &quot;https://www.cia.gov/library/publications/the-world-factbook/rankorder/2178rank.html&quot;&gt;proven reserves&lt;/a&gt;. From this we can see that world consumption is about 36.75 billion barrels of oil per year, and the total proven reserves is about 1.48 trillion barrels. If we do the simple calculation of just dividing reserves by consumption we get just over 40 years. This means that if oil consumption does not grow any more, we will run out of all the oil we have proven to exist in 2051. This seems like a long time away, however it is within one human lifetime: I will turn 65 in 2051.&lt;br/&gt;&lt;br/&gt;That is assuming that there will be no growth in consumption during those 40 years. Looking at &lt;a href = &quot;http://www.indexmundi.com/energy.aspx&quot;&gt;this page&lt;/a&gt; the average growth rate in oil consumption is 1.18% per year (using a &lt;a href = &quot;http://en.wikipedia.org/wiki/Geometric_mean&quot;&gt;geometric mean&lt;/a&gt; since this is a growth rate). If we predict that oil consumption will continue to rise at this rate, we will run out of our reserves a bit sooner: just under 33 years from now, sometime in 2044. This is less than half of our prediction from the Canadian example, and one sixth of the Canadian government&#39;s prediction of how long our oil supplies will last.&lt;br/&gt;&lt;br/&gt;How is it that the amount of time here is so much smaller than in the Canadian case? Why is it that the world oil reserves will somehow be drained sooner than the Canadian ones, a logical impossibility? The main culprit here is our assumption that Canadian oil production will continue to grow at 2.65% and not something higher. If you look at &lt;a href = &quot;https://www.cia.gov/library/publications/the-world-factbook/rankorder/2173rank.html&quot;&gt;global oil production by country&lt;/a&gt; you can see that four countries (Russia, the USA, China and Iran) all have much higher production than Canada but all have lower proven reserves; they will run out of their oil far sooner than we will. When that happens, consumers around the world who want oil will have to turn to somebody else. Will our 2.65% per year increase in production be able to satisfy those consumers once other sources start running out?&lt;br/&gt;&lt;br/&gt;As in the last post, I am stressing that this is not driven by ideology. There is no liberal or conservative bias here, it is just numbers from reasonably good sources and simple, widely known mathematics. You can repeat this analysis yourself and see that you will come to the same numbers. The R code for this one is available &lt;a href = &quot;https://gist.github.com/1530380&quot;&gt;here&lt;/a&gt;, you&#39;ll need the data that I listed above and then convert the CIA files from fixed-width format to CSV format.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/1514513733365123342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/1514513733365123342' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1514513733365123342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1514513733365123342'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/12/world-peak-oil.html' title='World Peak Oil'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-6763858519433301516</id><published>2011-12-26T20:39:00.000-05:00</published><updated>2013-05-18T11:22:02.716-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="economics"/><title type='text'>Canadian Peak Oil</title><content type='html'>One thing that interested me back in my university days was peak oil - the idea that at some point, our ability to produce oil will at some point peak and then decline. It seemed very logical to me that given a finite resource and an ever-increasing demand for it, we will eventually run out. Given the drastic consequences that could happen if we happened to run out of this resource that seems to be used &lt;i&gt;everywhere&lt;/i&gt;, it seemed like a good idea to be concerned about this problem and try to figure out how to at least minimize the damage should this disaster scenario come sometime soon.&lt;br/&gt;&lt;br/&gt;Today I&#39;m marginally wiser than I was then, so I like to verify myself if these types of things I hear through the media are true or not. I decided to look up some of the details about this whole peak oil thing and wonder, &quot;when would this whole thing start going down?&quot;&lt;br/&gt;&lt;br/&gt;I looked on Natural Resources Canada&#39;s web page to see some information about oil production. I found &lt;a href = &quot;http://www.nrcan.gc.ca/energy/sources/crude/1165&quot;&gt;this tidbit&lt;/a&gt; which says, &quot;Canada&#39;s oil reserves are sufficient to meet demand for the next 200 years at current rates of production.&quot; Nice! I suppose that means I don&#39;t have to care, and let the future generations figure out how they are going to deal with this problem.&lt;br/&gt;&lt;br/&gt;Right?&lt;br/&gt;&lt;br/&gt;Well, maybe not. The first thing we want to do is verify that this number is actually correct. After all, while we know that the government would &lt;i&gt;never&lt;/i&gt; lie to us, it&#39;s always a smart idea to figure things out for yourself in case somebody over there made a mistake.&lt;br/&gt;&lt;br/&gt;To figure out our rate of extraction, &lt;a href = &quot;http://www.nrcan.gc.ca/energy/sources/crude/1287#us&quot;&gt;this FAQ&lt;/a&gt; tells us that Canada currently produces about 2.5 million barrels of crude oil per day (consistent with some data that is mentioned below). To figure out how much oil Canada has proved to have, &lt;a href = &quot;http://www.eia.gov/emeu/international/reserves.html&quot;&gt;a 2010 report&lt;/a&gt; by the US Energy Information Association tells us that Canada currently has about 178 billion barrels of proven oil reserves that can be extracted, including the oil sands. If you take this number and divide it by the amount of oil we produce each day, we get approximately 195 years of producing oil; the number given by the government website is more or less correct.&lt;br/&gt;&lt;br/&gt;Does this mean all is well for the next 200 years? Well, not really. See, the bit that breaks this whole analysis is right in the quote taken from the government&#39;s FAQ: &quot;at current rates of production.&quot; The 200 year figure assumes that Canadian production of oil will not grow at all over the next 200 years. Intuitively that doesn&#39;t seem right, but let&#39;s be scientific about this. Maybe it is in fact true that oil production is constant.&lt;br/&gt;&lt;br/&gt;Doing a bit of a search with my trusty sidekicks Google and Wikipedia, I found some data &lt;a href = &quot;http://membernet.capp.ca/SHB/Sheet.asp?SectionID=3&amp;SheetID=233&quot;&gt;here&lt;/a&gt; on the website of the Canadian Association of Petroleum Producers that shows the yearly oil production in Canada from 1971 to 2010. Rather than describe it to you, here&#39;s a picture:&lt;br/&gt;&lt;br/&gt;&lt;a href = &quot;http://www.robbritton.com/wp-content/uploads/oil.png&quot;&gt;&lt;img src = &quot;http://www.robbritton.com/wp-content/uploads/oil.png&quot; alt = &quot;Canadian Oil Production&quot; width = &quot;400px&quot; /&gt;&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;If the government&#39;s assumption were true, this graph would be a flat line at 2.5. As you can see it is definitely not, in fact it seems to be increasing at a fairly quick rate!&lt;br/&gt;&lt;br/&gt;What happens to our numbers if we start increasing oil production each year? Let&#39;s find out.&lt;br/&gt;&lt;br/&gt;With a linear model, we get that it is increasing by about 0.0336 Mbbl, or 33 000 barrels of oil per year. If this trend continues, it means that the reserves will run out in...194 years. So one year less than if we assumed it would be flat.&lt;br/&gt;&lt;br/&gt;Of course, typically in economics it is assumed that economies grow &lt;i&gt;exponentially&lt;/i&gt;, not linearly. Since both population and productivity due to technology seem to increase at exponential rates, it a fairly safe assumption to make that production of anything increases at an exponential rate provided nothing stops it.&lt;br/&gt;&lt;br/&gt;When we use an exponential model, we can calculate that the oil production is growing at about 1.68% per year. If we extrapolate this out, it turns out our oil supply will run out after...87 years. That&#39;s a bit shorter than the last time frame! Even scarier for the people living in that time, we will use up the first half of our current amount in about 60 years, with the second half being used up in a short 27 year time frame! So in short, if production keeps up as it has been, then our grandchildren (assuming you&#39;re my age, I&#39;m 25) will see the day when the known oil deposits of Canada will run dry.&lt;br/&gt;&lt;br/&gt;In fact, there&#39;s another problem with this analysis. The data set we&#39;re using includes the 1970&#39;s with a massive oil boom followed by a collapse in the mid-70&#39;s that lasted until about 1980. If we re-run the exponential model after dropping the 1970&#39;s (so we are left with 30 years of data) the rate of increase goes up to 2.56% with an R&lt;sup&gt;2&lt;/sup&gt; of 0.98 (meaning a near perfect fit). With that rate of increase, our oil will run out in 70 years. This is a lot closer than the 200 years given by NR Canada.&lt;br/&gt;&lt;br/&gt;I tried to leave out any speculation from this post and just use numbers and math based on what has been happening and from those numbers, make a simple extrapolation to see what would happen should the existing trends continue. The growth rate of 2.56% per year may change in the future (up or down), which obviously would change the results of this simple analysis.&lt;br/&gt;&lt;br/&gt;To add my own little bit of speculation, from what I&#39;ve seen in the news I think that this rate of production will actually increase over time given the attitudes of the current Canadian government - as more projects such as the &lt;a href = &quot;http://en.wikipedia.org/wiki/Keystone_Pipeline&quot;&gt;Keystone pipeline&lt;/a&gt; get completed it will be even cheaper to transport oil into the United States and other countries from Canada. An economics 101 class will tell you that as the efficiency of supply increases, the amount of production will increase: as Canadians get better at shipping the oil to other places, more oil will be produced to ship.&lt;br/&gt;&lt;br/&gt;As always with my statistics-oriented posts, you can see the code &lt;a href = &quot;https://gist.github.com/1522394&quot;&gt;here&lt;/a&gt;. In the code you can see I did a linear model with the 1970&#39;s excluded but didn&#39;t talk about it here, it&#39;s because the exponential model fits both better with the data and better with economic theory.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/6763858519433301516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/6763858519433301516' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/6763858519433301516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/6763858519433301516'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/12/canadian-peak-oil.html' title='Canadian Peak Oil'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-5639841376528384540</id><published>2011-11-10T13:33:00.000-05:00</published><updated>2013-05-18T11:22:02.711-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="other"/><title type='text'>Chrome is the Best Thing for the Web since 2004</title><content type='html'>A little disclaimer to begin. I don&#39;t use Chrome. Despite the fact that it is damn fast, reliable, and tends to pick up new web features faster than any other browser, I prefer to limit my dependence on Google and so I will stick to the more open Firefox for my web needs.&lt;br/&gt;&lt;br/&gt;That doesn&#39;t mean that Chrome isn&#39;t great. However contrary to what you might think, I&#39;m not making the case that it is great because of the reasons I listed above. Instead, Chrome is great because it provides a worthwhile competitor to Firefox. It wasn&#39;t hard for Firefox to be amazing in 2004 when the only other widely used browser was IE6. It wasn&#39;t even fair. All that Mozilla had to do was make the browser not suck by having decent security, a Google search bar, extendability and tabbed browsing and you&#39;re set. Later on Firebug came out to make web development hugely more productive (think, Javascript error output that is actually useful!)&lt;br/&gt;&lt;br/&gt;However after that, Firefox didn&#39;t really change all that much. That is, until Chrome came out and the new browser &quot;arms race&quot; started. Now we are seeing huge improvements to what the web is capable of in record time - audio APIs, web sockets, 3D graphics, etc. We can now use the web to build rich applications that before we either needed Flash/Java, or we had to stick to building a plain-old desktop application. I&#39;ve even tried writing simple financial software using Javascript, and it actually works really well - you can receive a data feed directly from the exchange and have it appear in real time in an HTML table. Beautiful!&lt;br/&gt;&lt;br/&gt;What&#39;s even better about this arms race compared to the one in the 90&#39;s is that Mozilla and Google are actually cooperating to make sure that things are standardized. None of the old problems where Netscape would use one name but IE would use a different one - no, now we know that after the APIs become stable there will be efforts to standardize them across the more modern browsers.&lt;br/&gt;&lt;br/&gt;One thing I&#39;ve deliberately left out of the discussion is Internet Explorer. It continues to be developed, but as is typical of the IE team there doesn&#39;t seem to be a whole lot of effort to make it compatible with the things that Google and Mozilla are building. I think that the web would be better off if developers showed a bit of defiance and just decided to ignore Internet Explorer: focus on building amazing applications for the browsers that are actually pleasant to use. The users of those browsers will be much happier that way, and more people would migrate to those browsers when they see that they can have a much richer web experience that way. To quote some advice I&#39;ve heard from various VCs and startups, &quot;focus on making a few people very happy than trying to get a lot of ambivalent users.&quot;</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/5639841376528384540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/5639841376528384540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/5639841376528384540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/5639841376528384540'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/11/chrome-is-best-thing-for-web-since-2004.html' title='Chrome is the Best Thing for the Web since 2004'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-7838674489332919214</id><published>2011-11-08T14:31:00.000-05:00</published><updated>2013-05-18T11:22:02.698-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="finance"/><category scheme="http://www.blogger.com/atom/ns#" term="ironruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Trading with IronRuby</title><content type='html'>Over the last year I&#39;ve been using Ruby (more specifically IronRuby) to write algorithmic trading scripts. These aren&#39;t high-frequency algorithms, more implementations of various longer-term strategies using Ruby.&lt;br/&gt;&lt;br/&gt;There was poll over in an algorithmic trading forum on &lt;a href = &quot;http://www.elitetrader.com&quot;&gt;EliteTrader&lt;/a&gt; asking about what was the programming language of the future among Java, Scala, C#, F#, C++ and OCaml. A number of other people posted about other languages such as Python or Lisp, and how well they satisfied four criteria:&lt;ol&gt;&lt;li&gt;memory management (GC vs unmanaged)&lt;/li&gt;&lt;br/&gt;&lt;li&gt;concurrency model&lt;/li&gt;&lt;br/&gt;&lt;li&gt;static typing vs duck typing (or better yet, type inference)&lt;/li&gt;&lt;br/&gt;&lt;li&gt;object-oriented programming vs functional programming&lt;/li&gt;&lt;/ol&gt;I wrote a post on there about my experiences using IronRuby for trading, so I decided I would share that here as well:&lt;br/&gt;&lt;br/&gt;&lt;div style = &quot;border: 1px solid black; padding: 3px; background: #EEE&quot;&gt;&lt;br/&gt;I&#39;ve been using IronRuby for the last year, I&#39;ve found it works very well as I&#39;m able to go from idea to a working script in no time flat. Performance is not amazing, but the majority of my ideas do not require performance.&lt;br/&gt;&lt;br/&gt;For the evaluation (note that pretty much every point also applies to JRuby, the implementation of the language within the Java virtual machine):&lt;br/&gt;&lt;br/&gt;1. memory management (GC vs unmanaged)&lt;br/&gt;&lt;br/&gt;Uses .NET garbage collector, which is pretty solid. It tends to use a bit more memory than the equivalent VB.NET or C# script, but that&#39;s alright. RAM is cheaper than my time.&lt;br/&gt;&lt;br/&gt;2. concurrency model&lt;br/&gt;&lt;br/&gt;Again, uses .NET threads which are fairly solid. You can use any of the classes in the .NET library for concurrency.&lt;br/&gt;&lt;br/&gt;3. static typing vs duck typing (or better yet, type inference)&lt;br/&gt;&lt;br/&gt;Ruby uses duck typing. Mixins (aka traits in Scala) means you can write code in chunks and mix-and-match them per script. For example, you could have a SpreadTrade mixin that you just drop into a script and it will make the script do spread trading.&lt;br/&gt;&lt;br/&gt;There is a bit of clunkiness when interacting between C#/VB.NET code and IronRuby code due to type conversions and what-not - since Ruby collections can contain an arbitrary mix of types, collections are always treated as collections of Object when passing into C# code.&lt;br/&gt;&lt;br/&gt;4. object-oriented programming vs functional programming&lt;br/&gt;&lt;br/&gt;Ruby has a very nice blend of both. Absolutely everything is an object (including classes and primitives like integers), existing classes are open (you can add methods to existing classes), and closures passed to methods have a rather succinct syntax. For example, it is possible to build a library where the following code is valid:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;symbol.changes_by 2.5.percent do&lt;br/&gt;  # now within a closure with some code to execute when the stock changes by 2.5%&lt;br/&gt;end&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;At the same time, you still have all your nice functional programming techniques:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;# higher order functions:&lt;br/&gt;(1..5).map { |i| i * 2 }   # produces: [2, 4, 6, 8, 10]&lt;br/&gt;(1..100).select &amp;:odd?     # gets all the odd numbers from 1 to 100&lt;br/&gt;(1..100).inject &amp;:+        # produces the sum of 1 to 100&lt;br/&gt;&lt;br/&gt;# currying&lt;br/&gt;f = lambda { |a, b| a + b }&lt;br/&gt;g = f.curry[1]&lt;br/&gt;g[2]          # produces 3&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;Two new criteria that could be added:&lt;br/&gt;&lt;br/&gt;5. Meta-programming. In Ruby not only are things dynamically typed, but types themselves are dynamic. Rather than manually coding something every time, I can write one line within a class that will automatically generate the code that I want:&lt;br/&gt;&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;class SomeOrder&lt;br/&gt;  # this code will automatically generate code to cause orders of type SomeOrder to be&lt;br/&gt;  # hedged by an object of SomeOtherOrder&lt;br/&gt;  hedged_by SomeOtherOrder&lt;br/&gt;&lt;br/&gt;  # generate code that will cancel the order on some condition&lt;br/&gt;  cancel_if {&lt;br/&gt;    # market is tanking&lt;br/&gt;  }&lt;br/&gt;&lt;br/&gt;  # etc.&lt;br/&gt;end&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;br/&gt;This allows you to write code in a more declarative way, which can lead to less bugs as there are less moving parts you have to manually specify each time.&lt;br/&gt;&lt;br/&gt;6. Readability: As demonstrated in the examples above, I can show my scripts to non-programming traders and they are able to follow the strategy fairly easily. They may not understand the meaning of the punctuation, but the flow of the logic can be set up in a way similar to the way they might describe the strategy in English.&lt;br/&gt;&lt;br/&gt;Some downsides:&lt;br/&gt;- Like I said, performance is not amazing, it&#39;s on par with Python and the other scripting languages.&lt;br/&gt;- When coming from static languages it is inevitable you will get frustrated the first time you stub your toe on the dynamic typing system - you can get some weird bugs when you accidentally pass in a string instead of an array or something like that.&lt;br/&gt;- Those nice declarative meta-programming things can be rather tricky to implement within a library.&lt;br/&gt;- Finally, the language assumes that everybody knows what they&#39;re doing. It is possible for some people to write very bad code in Ruby that messes things up - for example, overriding the + operator for arrays to implement vector addition when the standard library has it defined as the array concatenation operator. Imagine your surprise when [1, 2] + [3, 4] produces [4, 6] instead of the expected [1, 2, 3, 4].&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;Out of the readers who are also Rubyists, what do you guys think about this topic?</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/7838674489332919214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/7838674489332919214' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7838674489332919214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7838674489332919214'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/11/trading-with-ironruby.html' title='Trading with IronRuby'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-2061787276420678219</id><published>2011-10-05T11:43:00.000-04:00</published><updated>2013-05-18T11:22:02.693-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="other"/><title type='text'>ProjectDrinks</title><content type='html'>I&#39;ve decided to start up the ProjectDrinks meetup again here in Montreal, if you&#39;re interested in coming down you can check out the details &lt;a href = &quot;http://www.projectdrinks.com/?p=11&quot;&gt;here&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/2061787276420678219/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/2061787276420678219' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/2061787276420678219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/2061787276420678219'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/10/projectdrinks.html' title='ProjectDrinks'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-7594137200281520692</id><published>2011-10-01T18:56:00.000-04:00</published><updated>2013-05-18T11:22:02.689-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Events in Javascript</title><content type='html'>One of the features of C# that I really enjoy is events. For the many folks out there who have never used C#, an event is an implementation of the observer pattern that allows objects to watch for certain notifications within other objects. For example in the Windows.Forms library the Button object has a Click event that you can bind an action to:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;  var button = new Button();&lt;br/&gt;  button.Click += (sender, ev) =&gt; {&lt;br/&gt;    MessageBox.Show(&quot;Hello, world!&quot;);&lt;br/&gt;  };&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;You can define events within your own classes and fire them easily:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;  public delegate void MyEventHandler();&lt;br/&gt;  public event MyEventHandler MyEvent;&lt;br/&gt;&lt;br/&gt;  //  ... lots of code ...&lt;br/&gt;&lt;br/&gt;  // ... in some method that triggers the event:&lt;br/&gt;    if (MyEvent != null){&lt;br/&gt;      MyEvent();&lt;br/&gt;    }&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;Turns out this is fairly easily implemented in Javascript. This code here should do the trick:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;function createEvent(eventName, obj){&lt;br/&gt;  var event = function() {&lt;br/&gt;    var ob;&lt;br/&gt;    for (var i = 0; i &lt; obj[eventName].observers.length; i++){&lt;br/&gt;      ob = obj[eventName].observers[i];&lt;br/&gt;      ob.apply(ob, arguments);&lt;br/&gt;    }&lt;br/&gt;  };&lt;br/&gt;&lt;br/&gt;  event.observers = [];&lt;br/&gt;&lt;br/&gt;  event.add = function(observer) {&lt;br/&gt;    event.observers.push(observer);&lt;br/&gt;  };&lt;br/&gt;&lt;br/&gt;  event.remove = function(observer) {&lt;br/&gt;    var i = event.observers.indexOf(observer);&lt;br/&gt;    if (i &gt;= 0){&lt;br/&gt;      event.observers.splice(i, 1);&lt;br/&gt;    }&lt;br/&gt;  };&lt;br/&gt;&lt;br/&gt;  obj[eventName] = event;&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;Now you can go like this:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;var obj = {};&lt;br/&gt;&lt;br/&gt;createEvent(&quot;test&quot;, obj);&lt;br/&gt;&lt;br/&gt;obj.test.add(function(){&lt;br/&gt;  alert(&quot;Hello, world!&quot;);&lt;br/&gt;});&lt;br/&gt;&lt;br/&gt;obj.test();&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;&lt;script type = &quot;text/javascript&quot;&gt;&lt;br/&gt;function createEvent(eventName, obj){&lt;br/&gt;  var event = function() {&lt;br/&gt;    var ob;&lt;br/&gt;    for (var i = 0; i &lt; obj[eventName].observers.length; i++){&lt;br/&gt;      ob = obj[eventName].observers[i];&lt;br/&gt;      ob.apply(ob, arguments);&lt;br/&gt;    }&lt;br/&gt;  };&lt;br/&gt;  event.observers = [];&lt;br/&gt;  event.add = function(observer) {&lt;br/&gt;    event.observers.push(observer);&lt;br/&gt;  };&lt;br/&gt;  event.remove = function(observer) {&lt;br/&gt;    var i = event.observers.indexOf(observer);&lt;br/&gt;    if (i &gt;= 0){&lt;br/&gt;      event.observers.splice(i, 1);&lt;br/&gt;    }&lt;br/&gt;  };&lt;br/&gt;  obj[eventName] = event;&lt;br/&gt;}&lt;br/&gt;var obj = {};&lt;br/&gt;createEvent(&quot;test&quot;, obj);&lt;br/&gt;obj.test.add(function(){&lt;br/&gt;  alert(&quot;Hello, world!&quot;);&lt;br/&gt;});&lt;br/&gt;&lt;/script&gt;&lt;br/&gt;You can try it by clicking &lt;a href = &quot;#&quot; onclick = &quot;obj.test(); return false&quot;&gt;here&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/7594137200281520692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/7594137200281520692' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7594137200281520692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7594137200281520692'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/10/events-in-javascript.html' title='Events in Javascript'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-7311949005532479915</id><published>2011-09-26T15:28:00.000-04:00</published><updated>2013-05-18T11:22:02.684-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="game-programming"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Crafty: Gaming Engine for Javascript</title><content type='html'>I started fiddling with this Javascript gaming library called &lt;a href = &quot;http://craftyjs.com/&quot;&gt;Crafty&lt;/a&gt;, which allows you to build simple video games using DOM or canvas elements. Up front I like it better than &lt;a href = &quot;http://gamequery.onaluf.org/&quot;&gt;gameQuery&lt;/a&gt; since it allows you to use canvas, but also because it seems to be much more of a framework rather than just a collection of jQuery extensions for gaming.&lt;br/&gt;&lt;br/&gt;The most interesting thing about the library though is the use of &lt;i&gt;components&lt;/i&gt;, which are essentially an implementation of Ruby&#39;s mixins in Javascript. A large number of built-in components support fancy things sprites, physics and input-related components that make an entity (such as a player) automatically respond to the arrow keys on the keyboard.&lt;br/&gt;&lt;br/&gt;You can even define your own components. For example, you could define a component called FollowsMouse which means the sprite will follow the mouse cursor.&lt;br/&gt;&lt;br/&gt;The main issue so far is that the documentation is sparse and the examples are not at all up-to-date. When you create an entity, you do it like this:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;obj = Crafty.e(&quot;list&quot;, &quot;of&quot;, &quot;included&quot;, &quot;components&quot;);&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;However it turns out that the capitalization style of components has changed:&lt;br/&gt;&lt;pre&gt;&lt;br/&gt;// examples say to do this:&lt;br/&gt;obj = Crafty.e(&quot;2D&quot;, &quot;canvas&quot;);&lt;br/&gt;// when in fact you do this:&lt;br/&gt;obj = Crafty.e(&quot;2D&quot;, &quot;Canvas&quot;);&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;These types of problems are very difficult to track down, since there is no failure notice when a required component doesn&#39;t exist. Instead, the system just ignores it and your entities don&#39;t render. I typically follow the adage, &quot;the bug is not in the library, despite how much it seems like it&quot; and yet, sometimes the bug is actually in the library (or in this case, the documentation).&lt;br/&gt;&lt;br/&gt;There is probably a few other hiccups, maybe I&#39;ll make a few tweaks to the library and send it over in hopes they&#39;ll merge a patch in.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/7311949005532479915/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/7311949005532479915' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7311949005532479915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7311949005532479915'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/09/crafty-gaming-engine-for-javascript.html' title='Crafty: Gaming Engine for Javascript'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-4594327706869835000</id><published>2011-09-12T15:23:00.000-04:00</published><updated>2013-05-18T11:22:02.679-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Ruby&amp;#39;s instance_eval and Structured Configuration Files</title><content type='html'>Recently at work I was setting up a section of the program involving a user-configurable GUI element. Initially I thought about using something like XML to handle this, however if I went that route I&#39;d have to manage parsing the XML through some library, traversing the XML tree, and create some sort of GUI element based on what type of node it was, what the attributes were, etc.&lt;br/&gt;&lt;br/&gt;On top of that it was highly likely that the requirements for this GUI system would change and the level of sophistication behind the GUI system would increase - buttons would need to do more complicated tasks that could potentially be arbitrary. Having a hard-coded system in C# would not be feasible since tweaking logic would require a re-compile and an application restart.&lt;br/&gt;&lt;br/&gt;I decided that since the system already had an IronRuby install built in, perhaps I could do this configuration file in Ruby as well. Given an XML configuration file that looks like this:&lt;pre&gt;&amp;lt;group name=&quot;Buttons&quot;&amp;gt;&lt;br/&gt;  &amp;lt;line&amp;gt;&lt;br/&gt;    &amp;lt;button text=&quot;Cool Script&quot;&amp;gt;&lt;br/&gt;      &amp;lt;something_crazy_and_awesome /&amp;gt;&lt;br/&gt;    &amp;lt;/button&amp;gt;&lt;br/&gt;  &amp;lt;/line&amp;gt;&lt;br/&gt;&amp;lt;/group&gt;&lt;/pre&gt;I could translate this to Ruby that looks like this:&lt;br/&gt;&lt;br/&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Buttons&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;n&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Cool Script&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;&lt;br/&gt;      &lt;span class=&quot;n&quot;&gt;something_crazy_and_awesome&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;On top of that in order to use this configuration file in a program I don&#39;t actually need to parse the file, I can just execute it within the context of different objects. For the dialog box that allows the user to set up the configuration I can just execute the Ruby code within that dialog box object and it will automatically create the elements that allow the user to change the configuration. Then in the part of the application where the user actually uses the configuration, I can just execute the file again but with a different definition of &lt;code&gt;group&lt;/code&gt;, &lt;code&gt;line&lt;/code&gt;, etc. that construct the proper GUI elements.&lt;br/&gt;&lt;br/&gt;This is not just applicable to GUI elements, you can use this for anything that uses some sort of structured configuration. Rake uses this to great effect with tasks. But how would you go about implementing this pattern?&lt;br/&gt;&lt;br/&gt;Turns out it&#39;s really simple using &lt;code&gt;instance_eval&lt;/code&gt;.  Here&#39;s an example that constructs the GUI element (this is in&lt;br/&gt;IronRuby so it uses .NET for GUI construction):&lt;br/&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GroupBuilder&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;vi&quot;&gt;@group_box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GroupBox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Controls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@group_box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;nb&quot;&gt;instance_eval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;no&quot;&gt;LineBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@group_box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LineBuilder&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;kp&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:panel&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;c1&quot;&gt;# in the GUI environment we use a panel for adding things&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;vi&quot;&gt;@panel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Panel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Controls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@panel&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;    &lt;span class=&quot;nb&quot;&gt;instance_eval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;no&quot;&gt;ButtonBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@panel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;  &lt;span class=&quot;c1&quot;&gt;# ... anything else that can be placed in a line ...&lt;/span&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ButtonBuilder&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;c1&quot;&gt;# create a button&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;n&quot;&gt;btn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;c1&quot;&gt;# bind the click event of the button to execute the&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;c1&quot;&gt;# Ruby code within the block&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;n&quot;&gt;btn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Click&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance_eval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Controls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;btn&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;something_crazy_and_awesome&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;c1&quot;&gt;# do something crazy and awesome&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScriptProcessor&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;script&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;vi&quot;&gt;@control&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;control&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;nb&quot;&gt;instance_eval&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;br/&gt;    &lt;span class=&quot;no&quot;&gt;GroupBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@control&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;br/&gt;&lt;/pre&gt;&lt;/div&gt;To do all this stuff, you can just create a ScriptProcessor object, pass in a .NET control and a script filename:&lt;br/&gt;&lt;br/&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;br/&gt;&lt;span class=&quot;no&quot;&gt;ScriptProcessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;my_config_file.rb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;br/&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Show&lt;/span&gt;&lt;br/&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;For each type of nested element you can create a class which define a method for the various types of sub-elements that you are allowed to have. Each of those methods will then handle the processing that needs to happen when the system sees an element of that type.&lt;br/&gt;&lt;br/&gt;I think you could probably do this without classes and just use lambdas, but I think the code is clearer when you have objects since it is very explicit as to what each object is for.&lt;br/&gt;&lt;br/&gt;Doing this with C# is a bit trickier since C# doesn&#39;t have instance_eval, but it turns out you can have a bit of a hack in order to get it to work quite well. I&#39;ll write up a quick post about this at a later date.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/4594327706869835000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/4594327706869835000' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/4594327706869835000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/4594327706869835000'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/09/ruby-instanceeval-and-structured.html' title='Ruby&amp;#39;s instance_eval and Structured Configuration Files'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-1578070234001066752</id><published>2011-08-30T11:09:00.000-04:00</published><updated>2013-05-18T11:22:02.674-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="vim"/><title type='text'>VimConf</title><content type='html'>I like Vim. Especially learning new tricks with it. Do you?&lt;br/&gt;&lt;br/&gt;If yes, check out &lt;a href = &quot;http://www.vimconf.org/?s=2T0&quot;&gt;VimConf&lt;/a&gt;, it&#39;s an online conference where people show all sorts of tips about using Vim, extending it with scripting, etc.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/1578070234001066752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/1578070234001066752' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1578070234001066752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1578070234001066752'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/08/vimconf.html' title='VimConf'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-1011098120533253465</id><published>2011-08-25T10:43:00.000-04:00</published><updated>2011-08-25T10:43:03.277-04:00</updated><title type='text'>Reincarnated Blog</title><content type='html'>It&#39;s been a long time since I posted. About four months to be exact. I have a series of excuses, but they are mostly irrelevant so I won&#39;t really go into them here.&lt;br /&gt;
&lt;br /&gt;
Instead I&#39;ll announce I&#39;m starting a new blog. In an attempt to become less reliant on Google for services I&#39;ve decided to move the blog onto a server where I have control over things: &lt;a href = &quot;http://robbritton.com&quot;&gt;robbritton.com&lt;/a&gt;. The blog is not likely to have the same content as this one, there will be a lot less Linux/programming/statistics posts and more on just random stuff that I like. If you feel like hearing about those sorts of things feel free to start following that one (which I hope to start updating on a semi-regular basis).</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/1011098120533253465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/1011098120533253465' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1011098120533253465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/1011098120533253465'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/08/reincarnated-blog.html' title='Reincarnated Blog'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-8877860269400119071</id><published>2011-08-25T10:32:00.000-04:00</published><updated>2013-05-18T11:22:02.669-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="other"/><title type='text'>Project Euler</title><content type='html'>I&#39;ve already managed to fail at my 250 words per day project, since I haven&#39;t posted in a while. That&#39;s alright I suppose, maybe it will take a bit of time to get into it. Anyway, here&#39;s another brief post about something I discovered the other day: a site called &lt;a href = &quot;http://projecteuler.net/&quot;&gt;Project Euler&lt;/a&gt;. This site has a whole bunch of mathematical problems that you can solve via programming.&lt;br/&gt;&lt;br/&gt;The fun part about this site is that many of the problems are fairly easily solvable using a recursive solution. I find that in everyday coding, you don&#39;t really do much development using recursive functions. This is disappointing because it really is quite an elegant way to solve problems! For example, &lt;a href = &quot;http://projecteuler.net/index.php?section=problems&amp;id=28&quot;&gt;problem 28&lt;/a&gt; might not seem like a recursive problem, but in fact can be solved trivially using a recursive solution! I enjoy &quot;games&quot; where I begin to think in this way, maybe it helps stroke my nerd ego a little. On top of that, the focus is also on efficiency; it is possible for a computer to solve any of the problems within one minute (the one-minute rule) provided you&#39;re using an efficient algorithm.&lt;br/&gt;&lt;br/&gt;Most of the problems, if not all, are based on work done by Euler. This includes problems involving prime numbers, combinatorics, factorials and other tasty bits of number theory. These are very useful bits of math to learn, and the harder questions on the site force you to do a bit of research in order to find a proper solution.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/8877860269400119071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/8877860269400119071' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/8877860269400119071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/8877860269400119071'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/08/project-euler.html' title='Project Euler'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-2624542227992966779</id><published>2011-08-17T11:52:00.000-04:00</published><updated>2013-05-18T11:22:02.664-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="other"/><title type='text'>250 Words</title><content type='html'>I&#39;ve decided to start up my own little project based on the idea at the site &lt;a href = &quot;http://750words.com&quot;&gt;750words&lt;/a&gt;, which is a game where you&#39;re supposed to write 750+ words per day to engage the brain juices. I remember when I first started going hardcore on &lt;a href = &quot;http://lovehateubuntu.blogspot.com&quot;&gt;my old blog&lt;/a&gt; this was my goal: to just write about random things and see what happens. It worked pretty well, I ended up getting a few articles posted on reddit and other silly places like that and basically learning how retarded some of my ideas were (or how retarded some other people on the Internet are).&lt;br/&gt;&lt;br/&gt;From what my teachers and professors have told me I&#39;ve always been very concise with my writing, so I think I&#39;ll shorten it from 750 words to 250 words. That way if I don&#39;t have a lot to say on a topic I have a lower bar to shoot for, but also to keep things bite-sized since reading long blocks of text that aren&#39;t incredibly well written and aren&#39;t really about anything is not always the most fun thing to do.&lt;br/&gt;&lt;br/&gt;For the topics I&#39;ll probably just be writing random posts about stuff that I&#39;ve been thinking about, things that interest me, or maybe random happenings in life that are not too personal to tell the world about. I want to try and avoid rants since those tend to be annoying to read and there are enough rants on the web already (including on my old blog) that more of them would just pollute the Internet and not be terribly constructive. I&#39;d also like to reserve my old blog for HOWTOs since I&#39;m tired of writing about how to make the world a better place or how to help random folks because that is what discouraged me from writing before: the worry that what I&#39;m saying isn&#39;t good enough for the world means I avoid just writing for the sake of writing, which is the main reason why I started my blog in the first place! So I&#39;ll stick to talking about things that I like to talk about, and anybody who cares to listen can do so.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/2624542227992966779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/2624542227992966779' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/2624542227992966779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/2624542227992966779'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/08/250-words.html' title='250 Words'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-757415918236037510</id><published>2011-08-05T10:47:00.000-04:00</published><updated>2013-05-18T11:22:02.657-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="other"/><title type='text'>New Blog</title><content type='html'>I&#39;ve started up a new blog here to replace my &lt;a href = &quot;http://lovehateubuntu.blogspot.com&quot;&gt;old one&lt;/a&gt;. The old one was initially about Linux and my joys/woes with it (hence the name of the blog) but slowly over time posts about programming, statistics, economics, etc. took over and the content of the blog changed.&lt;br/&gt;&lt;br/&gt;Unfortunately I ended up talking about things that I thought other people were interested in, and not so much about things that I was interested in. Eventually I just lost inspiration and stopped writing. This is a problem because I like to write and share stuff that I&#39;m interested in, so this new blog is an attempt to start doing that again.&lt;br/&gt;&lt;br/&gt;I suppose I could have just continued writing on the old blog, but I don&#39;t really want to because the old blog has a Linux brand to it that I want to get away from and also I&#39;m slowly losing trust in Google so I&#39;d rather host the blog on my own server. Plus the fact that this blog has my own name as the domain lends some credibility to it!&lt;br/&gt;&lt;br/&gt;Anyway if you&#39;ve liked some of the things I posted about in my old blog (fractals, some of the stats stuff) then feel free to stick around! Otherwise I hate to disappoint, but I probably won&#39;t be writing too much on Linux or how-to-be-a-better-programmer or things like that.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/757415918236037510/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/757415918236037510' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/757415918236037510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/757415918236037510'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/08/new-blog.html' title='New Blog'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-5520065504123640751</id><published>2011-04-23T16:31:00.000-04:00</published><updated>2011-04-23T16:31:32.066-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="computers"/><category scheme="http://www.blogger.com/atom/ns#" term="programming"/><title type='text'>ProjectDrinks, Take 2</title><content type='html'>Just a reminder to anybody who is interested, this Monday is the second ProjectDrinks meetup. It will be at 6:30pm at Trois-Brasseurs, at the corner of St. Catherine and Crescent, downtown Montreal.&lt;br /&gt;
&lt;br /&gt;
Last time people had some trouble finding the table, so it will be the one with a laptop on it.&lt;br /&gt;
&lt;br /&gt;
I was contacted last time about &lt;a href = &quot;http://notmanhouse.pbworks.com/w/page/37549246/Homepage&quot;&gt;Notman House&lt;/a&gt;, which is supposedly a meeting place for web developers and tech entrepreneurs. It looks kinda neat, although the idea of the house seems to be very startup-oriented, which isn&#39;t quite in the same direction that I&#39;d like to see ProjectDrinks go. I&#39;ll check it out at some point once I&#39;m done exams and let people know how it goes.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/5520065504123640751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/5520065504123640751' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/5520065504123640751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/5520065504123640751'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/04/projectdrinks-take-2.html' title='ProjectDrinks, Take 2'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-7518275066975885675</id><published>2011-04-21T16:07:00.001-04:00</published><updated>2011-04-21T16:07:30.522-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="economics"/><category scheme="http://www.blogger.com/atom/ns#" term="statistics"/><title type='text'>Bad Statistics: My Mistake</title><content type='html'>I was watching &lt;a href = &quot;http://www.youtube.com/watch?v=akVL7QY0S8A&amp;t=15m30s&quot;&gt;this video&lt;/a&gt; today and one comment the speaker made was that men&#39;s incomes have not increased but women&#39;s incomes have. I thought this was interesting and decided to look into it.&lt;br /&gt;
&lt;br /&gt;
However while I was thinking about it I realized that in &lt;a href = &quot;http://lovehateubuntu.blogspot.com/2011/02/wages-over-years.html&quot;&gt;my last wage analysis&lt;/a&gt; I was using 1986 vs. 2006, which wasn&#39;t a great idea.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s why. What&#39;s the difference between this graph:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVB67Bg4354yeyu4q6fhSq6yyjeSiMiffpuY5_WVZyPHTLP5folIhPzTzwAg5B1pg4q5EoaBDEdKUx25YyxyoSfs96ytQ_eYP_R3kfW2pMfc2nmVFMwswmZeCQfpvkgUmtLFDx5XOs7zY/s1600/line.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;211&quot; width=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVB67Bg4354yeyu4q6fhSq6yyjeSiMiffpuY5_WVZyPHTLP5folIhPzTzwAg5B1pg4q5EoaBDEdKUx25YyxyoSfs96ytQ_eYP_R3kfW2pMfc2nmVFMwswmZeCQfpvkgUmtLFDx5XOs7zY/s320/line.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;And this one:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFFXAh6DBxXHbwxUUjsmmrkFgH6pGxV6Wo5mBoBckI0qFiRv7vMbI2Q6U4vZylXzoBK4_Lxgogfksfdew5OI9hQsui47cw3fcjxZwUJ0-C2lCNVz0Rgjudcx2kgfAfp2iBxPIP-Q7GFyo/s1600/sine.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;212&quot; width=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFFXAh6DBxXHbwxUUjsmmrkFgH6pGxV6Wo5mBoBckI0qFiRv7vMbI2Q6U4vZylXzoBK4_Lxgogfksfdew5OI9hQsui47cw3fcjxZwUJ0-C2lCNVz0Rgjudcx2kgfAfp2iBxPIP-Q7GFyo/s320/sine.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Although these graphs look nothing alike, when you only have two data points you can&#39;t actually tell which of the two graphs created this.&lt;br /&gt;
&lt;br /&gt;
That&#39;s the issue with my last analysis. We have these weird things in the economy called &quot;business cycles&quot; which you may have heard of, where the economy is doing &quot;well&quot; or &quot;poorly&quot;. Unfortunately these cycles could screw up the analysis that I did before since it could be possible that wages haven&#39;t gone up at all in a general sense, it could have just been the case that in different economic states in 1986 and 2006 rather than that wages have actually gone up. In 2006 for example, the Canadian economy was doing very well due to high commodity prices, where 1986 wasn&#39;t a very big boom period.&lt;br /&gt;
&lt;br /&gt;
This is an example of a very basic statistical problem: model misspecification. In many cases when you&#39;re doing statistics you have some sort of model that you are trying to fit the data to. If the model you propose is correct then cool, but if it is incorrect you might not know. Many statistical procedures such as least-squares regression will still work when you give a bad model, but will give meaningless results. Unfortunately it might be the case that the results look reasonable, but are still completely incorrect - this is the most dangerous case, since without further analysis there is no real indication that your results are wrong. Fortunately there are tests like the &lt;a href = &quot;http://en.wikipedia.org/wiki/Ramsey_RESET_test&quot;&gt;RESET test&lt;/a&gt; that can test for this kind of thing, however you have to know about them in order to actually use them (obviously). They also aren&#39;t foolproof - on one hand they will tell you that you do have misspecification, on the other hand they will tell you that you &lt;i&gt;might&lt;/i&gt; not have it. As with most things in statistics, you don&#39;t get a crisp yes/no answer.&lt;br /&gt;
&lt;br /&gt;
The moral here is that even if you have a representative sample and you have good intentions (ie. not screwing with the results so things look the way you want them to) you can still get bad results by applying the wrong procedures.&lt;br /&gt;
&lt;br /&gt;
Back to the original question: how have wages changed over the years with respect to men and women? Keeping in mind all the stuff that I just said, here are the results:&lt;br /&gt;
&lt;table cellspacing = &quot;5&quot;&gt;&lt;tr&gt;&lt;th colspan=&quot;3&quot;&gt;Median income (2010 dollars)&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;1986&lt;/th&gt;&lt;th&gt;2006&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Men&lt;/th&gt;&lt;td&gt;37472 (106)&lt;/td&gt;&lt;td&gt;38442 (182)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Women&lt;/th&gt;&lt;td&gt;19331 (72)&lt;/td&gt;&lt;td&gt;25628 (87)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;The numbers in brackets are the standard errors, this is how statistics are reported in real papers. If you ever read a paper that reports statistics with comparisons, you should see if they show these numbers. If not, you can&#39;t really be too sure about the comparisons - a good example is a &lt;a href = &quot;http://www.ivir.nl/publications/vaneijk/Communications&amp;Strategies_2010.pdf&quot;&gt;survey on game piracy&lt;/a&gt; that &lt;a href = &quot;http://lovehateubuntu.blogspot.com/2010/05/piracy-boosts-game-sales-yeah-right.html&quot;&gt;I critiqued&lt;/a&gt; a while back.&lt;br /&gt;
&lt;br /&gt;
So women&#39;s wages have gone up a fair bit, while men&#39;s wages have not - consistent with the claim in the video. Whether this is a general trend or some blip due to the time periods chosen we can&#39;t say with the data here. I can probably find data if I dig around a bit if people are curious.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/7518275066975885675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/7518275066975885675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7518275066975885675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/7518275066975885675'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/04/bad-statistics-my-mistake.html' title='Bad Statistics: My Mistake'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVB67Bg4354yeyu4q6fhSq6yyjeSiMiffpuY5_WVZyPHTLP5folIhPzTzwAg5B1pg4q5EoaBDEdKUx25YyxyoSfs96ytQ_eYP_R3kfW2pMfc2nmVFMwswmZeCQfpvkgUmtLFDx5XOs7zY/s72-c/line.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-4629876126827312317</id><published>2011-04-18T14:36:00.003-04:00</published><updated>2011-04-18T14:38:11.874-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><title type='text'>Fixing a Dead MySQL Server on Ubuntu</title><content type='html'>I&#39;m doing some freelance work for a company and unfortunately the other day their DB server crapped out. On top of that, there was some issues with the backup script, so the last backup done was quite some time ago.&lt;br /&gt;
&lt;br /&gt;
Fortunately though, the hard drive was still intact. Here is a little guide to restoring your MySQL DB in the case that your DB server dies and you have no backups. This is a guide for Ubuntu server 10.04, but it shouldn&#39;t be too different with other versions of Ubuntu or other Linux distributions.&lt;br /&gt;
&lt;br /&gt;
There is one requirement here: the hard drive still needs to work. If the hard drive is toast, then you&#39;re in trouble.&lt;br /&gt;
&lt;br /&gt;
1) We had another computer that wasn&#39;t being used that had been purchased to be set up as a backup server. It wasn&#39;t set up yet, so I just stuck Ubuntu Server on it and plugged the old hard drive in.&lt;br /&gt;
2) Make sure MySQL is installed: sudo apt-get install mysql-server&lt;br /&gt;
3) Stop the MySQL server: sudo /etc/init.d/mysql stop&lt;br /&gt;
4) MySQL keeps the database files in /var/lib/mysql. Copy these from the old hard drive to the new hard drive. It might be a good idea to not copy over /var/lib/mysql/mysql, however I didn&#39;t have any problems after copying that over (yet). Try it and if the database doesn&#39;t work, copy that folder too. Also, don&#39;t copy over any .pid files.&lt;br /&gt;
5) Set permissions: sudo chown mysql:mysql -R /var/lib/mysql/*&lt;br /&gt;
6) Restart the MySQL server: sudo /etc/init.d/mysql start&lt;br /&gt;
&lt;br /&gt;
Now the MySQL server should be just like it was before the system died. If you didn&#39;t copy over the /var/lib/mysql/mysql folder then you&#39;ll have to recreate any users that you had. If the whole thing just doesn&#39;t work then just copy that folder too.&lt;br /&gt;
&lt;br /&gt;
Hopefully this saves some people some pain! I was particularly annoyed since I forgot step 5, so the MySQL server was able to list the other databases but kept saying that there were no tables in any of them. Not good! In the end it just turned out to be a permissions issue which is no big deal.&lt;br /&gt;
&lt;br /&gt;
Anyway the more important thing to take out of all this is to make sure that your backup scripts work.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/4629876126827312317/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/4629876126827312317' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/4629876126827312317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/4629876126827312317'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/04/fixing-dead-mysql-server-on-ubuntu.html' title='Fixing a Dead MySQL Server on Ubuntu'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-165807313160822069.post-6577237506817976489</id><published>2011-04-17T11:44:00.000-04:00</published><updated>2011-04-17T11:44:32.156-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="programming"/><title type='text'>Empirical SoEn is Hard: Cost</title><content type='html'>In economics, there is a small sub-branch called &lt;a href = &quot;http://en.wikipedia.org/wiki/Experimental_economics&quot;&gt;experimental economics&lt;/a&gt;, which focuses on applying the experimental method to better understand economic phenomena. It has had some interesting results in small cases - especially in the field of game theory with things like the &lt;a href = &quot;http://en.wikipedia.org/wiki/Ultimatum_game&quot;&gt;ultimatum game&lt;/a&gt; - but most of the papers I&#39;ve read are done at such a small or simple scale that they don&#39;t really apply to a real economy. In order to make the results more interesting, the number of people involved must be a bit higher, and the experiments need to be done with a longer timeline. Unfortunately, the cost of this is extremely prohibitive (university departments are typically strapped for cash).&lt;br /&gt;
&lt;br /&gt;
I&#39;ve done a lot less reading of software engineering papers, but in my head it also seems like cost would pose a very large problem on empirical software engineering research. You could do some simple experiments with small groups of developers for small projects, however in reality many projects take large groups of developers working full-time months or even years to complete. Having a researcher pay these developers to do experiments might be prohibitively expensive. On top of that to be able to make any decent claims, you&#39;ll need to do a rather large number of these experiments which just blows the cost of everything through the roof.&lt;br /&gt;
&lt;br /&gt;
At this point you can&#39;t even use experiments anymore to do detailed study of software engineering. In the business world where you might have the resources to do basic experiments with large-scale projects, you typically have an aversion to risk and so businesses typically won&#39;t go too far from &quot;proven&quot; techniques since they may or may not increase the costs of doing business.&lt;br /&gt;
In economics typically we rely on observational data to do our analysis: we can collect data from the actual economy and analyze it, however we can&#39;t reach out and change whatever parameter we like to see how it will affect things. We also can&#39;t &quot;start over&quot; to see what happens if we change a few of the initial conditions: unless somebody develops time travel and goes back to 1950 to fiddle with unemployment rates or government policy to answer &quot;what-if&quot; questions. You can&#39;t impose controls the same way that you can when experimenting.&lt;br /&gt;
&lt;br /&gt;
I believe that software engineers are in the same boat. Due to cost concerns, you must rely more on observing actual software engineers at work than in the laboratory. This comes with all the problems with observational data: you can&#39;t go in and change the number of developers, or swap developers out with developers of different skill levels, or any of these other things that you might be able to try in an experiment. Also in observational data it is often the case that not just one thing changes at a time: sometimes one factor will change, but another will change at the same time since they are correlated - it is difficult to distinguish the effects of one variable from the effects of another when you aren&#39;t able to hold them fixed.</content><link rel='replies' type='application/atom+xml' href='http://lovehateubuntu.blogspot.com/feeds/6577237506817976489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/165807313160822069/6577237506817976489' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/6577237506817976489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/165807313160822069/posts/default/6577237506817976489'/><link rel='alternate' type='text/html' href='http://lovehateubuntu.blogspot.com/2011/04/empirical-soen-is-hard-cost.html' title='Empirical SoEn is Hard: Cost'/><author><name>Rob Britton</name><uri>http://www.blogger.com/profile/06467713562648469830</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS3SO2NobANa50Akm1IvXbqmdq8WlEQLQBAWr9IWY9y3mUI6iQ9rkwdwM9PkIYbbZQTpKyeFvd6Fn8Wk19Z2eANdQTrrUubf4gClJVxHISkhdO23Zrjd_mxgZAUVThU_U/s113/profilepic.jpeg'/></author><thr:total>0</thr:total></entry></feed>