<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title type="html">dira &amp;sdot; geek &amp;sdot; girl</title>
  <link href="http://dira.ro" />
  <author>
    <name>Irina Dumitrascu</name>
  </author>
  <id>http://dira.ro/</id>
  <updated>2013-04-29</updated>
  
    
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/AlmostGeek-Girl" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="almostgeek-girl" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.newsalloy.com/?rss=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.newsalloy.com/subrss3.gif">Subscribe with NewsAlloy</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.yourminis.com/subscribe.aspx?u=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.yourminis.com/images/addtoyourminisbadge.gif">Subscribe with Yourminis.com</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://download.attensa.com/app/get_attensa.html?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.attensa.com/blogs/attensa/WindowsLiveWriter/BadgeredintoBadges_10C02/attensa_feed_button5.gif">Subscribe with Attensa for Outlook</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://hub.netomat.net/account/account.autoSubscribe.jspa?urls=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.netomat.net/blogger/images/icon_netomat_feedbutton.gif">Subscribe with netomat Hub</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.flurry.com/pushRssFeed.do?r=fb&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.flurry.com/images/flurry_rss_logo2.gif">Subscribe with Flurry</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2FAlmostGeek-Girl" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><entry>
      <title>GMap_to_static: one-click static maps creation</title>
      <link href="http://dira.ro/2010/06/01/gmap_to_static-one-click-static-maps-creation" />
      <id>tag:dira.ro,2010-06-01:/2010/06/01/gmap_to_static-one-click-static-maps-creation</id>
      <updated>2010-06-01T12:16:22Z</updated>
      <content type="html">&lt;p&gt;&lt;a href="http://github.com/dira/gmap_to_static"&gt;GMap_to_static&lt;/a&gt; is a bookmarklet for creating a static map that looks just like a given dynamic Google Map. It is useful when you want to embed a Google Map as a ligthweight image, not as a full frame.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: In early 2011 this tool stopped working, as more aggressive minification of the map information hid the essential properties used by the algorithm.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Go to &lt;del&gt;&lt;a href="http://dira.ro/code/GMap-to-static/"&gt;dira.ro/code/GMap-to-static&lt;/a&gt; to install it and&lt;/del&gt; &lt;a href="http://github.com/dira/gmap_to_static"&gt;github&lt;/a&gt; to watch the project.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s how it works:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://img.skitch.com/20100610-1mbf5uehns3jn1a8c3ipwpdr2k.jpg" class="has_border" alt="" /&gt;&lt;/p&gt;
&lt;h2&gt;Why I wanted it&lt;/h2&gt;
&lt;p&gt;In order to create a Static Map image, you need the coordinates of all your markers and paths.&lt;/p&gt;
&lt;p&gt;I already had a &lt;a href="http://maps.google.com/maps/ms?ie=UTF8&amp;amp;hl=en&amp;amp;msa=0&amp;amp;msid=111625292422398641920.000474caf35a9ddb91aba&amp;amp;ll=-26.588527,-65.566406&amp;amp;spn=78.257793,157.324219&amp;amp;z=3"&gt;map&lt;/a&gt; with a lot of nice colorful markers spread across South America. But there is no tool to export it as a static map, so I was left with manually getting the coordinates of each marker&amp;#8230; or writing a tool to get them.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://maps.google.com/maps/api/staticmap?maptype=roadmap&amp;amp;zoom=2&amp;amp;size=196x237&amp;amp;center=-26.431228,-55.546875&amp;amp;sensor=false&amp;amp;markers=color:blue|-34.608,-58.373|-31.399,-64.182|-26.431,-62.358|-25.691,-54.602|-33.015,-58.519|-23.161,-65.215|-41.000,-71.500|-29.612,-67.939|-29.801,-67.828|-25.944,-65.733|-22.663,-66.237|-31.399,-64.182|-38.887,-71.185|-33.300,-66.349|-49.323,-72.891|-3.840,-32.411|-37.980,-57.590|-36.370,-56.718|-38.959,-68.071|-42.833,-71.833|-45.789,-68.993|-50.233,-68.917|-39.255,-68.774|-39.917,-71.417|-49.283,-73.083|-50.352,-72.257|-44.040,-65.226&amp;amp;markers=color:0x67dddd|-50.982,-72.499|-23.282,-68.862|-40.044,-72.773|-33.071,-71.609|-42.492,-73.790|-50.982,-72.499|-51.720,-72.484|-33.200,-70.633&amp;amp;markers=color:yellow|-12.383,-75.410|-12.039,-72.510|-12.297,-77.344&amp;amp;markers=color:0xce579a|-0.857,-78.618|-0.923,-78.223|-1.077,-80.618&amp;amp;markers=color:red|-3.250,-78.838&amp;amp;markers=color:purple|-34.814,-54.932&amp;amp;markers=color:0x00e64d|-25.416,-49.242|-29.362,-50.813" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;I boldly chose the &amp;#8220;write a tool&amp;#8221; option.&lt;/p&gt;
&lt;h2&gt;But it&amp;#8217;s not a piece of cake&lt;/h2&gt;
&lt;p&gt;The good news is that calling &lt;code&gt;window.gApplication.getMap()&lt;/code&gt; in a Google Maps page will return the current map.&lt;/p&gt;
&lt;p&gt;The bad news is that most of its properties and functions have been minified to cruel one or two-letter identifiers. So, except &lt;code&gt;getBounds&lt;/code&gt;, &lt;code&gt;getCenter&lt;/code&gt; and some conversion functions, there are no recognizable names in sight.&lt;/p&gt;
&lt;p&gt;Enthusiastically digging through the tree of minified JS properties, I found out that the &lt;strong&gt;markers&lt;/strong&gt; are minified too, but only partially. They still have some typical functions, like &lt;code&gt;infoWindow&lt;/code&gt; and &lt;code&gt;latlng&lt;/code&gt;, exposed fullname.&lt;/p&gt;
&lt;p&gt;Quite a handy discovery, but relying on a path like &lt;code&gt;map.Kd.St[0]&lt;/code&gt; is not a long-term solution. The path will probably change each time Google Maps is deployed.&lt;/p&gt;
&lt;p&gt;Luckily, backtracking was invented for this kind of tasks. So, I&amp;#8217;m searching the entire map object tree, looking for properties that &amp;#8220;quack&amp;#8221; like a marker. Finders, keepers!&lt;/p&gt;
&lt;p&gt;Once the secret of markers is exposed, a similar strategy can be applied to &lt;strong&gt;paths and shapes&lt;/strong&gt;. They too quack in a specific way, as they are the only ones having the function &lt;code&gt;getVertex&lt;/code&gt;. The difference is that paths have the property &lt;code&gt;name&lt;/code&gt;, while shapes don&amp;#8217;t. &lt;del&gt;However, shapes are not yet supported by the Static Maps &lt;span class="caps"&gt;API&lt;/span&gt;, so only their contour is rendered in the static image.&lt;/del&gt;&lt;/p&gt;
&lt;h2&gt;Guessing the zoom level&lt;/h2&gt;
&lt;p&gt;Another property that is minified is the zoom level. Unfortunately, it is just a number, so the quack-based detection does not really work to find it.&lt;/p&gt;
&lt;p&gt;I observed that the map&amp;#8217;s longitude span (in degrees) and its width (in pixels) are proportional within the same zoom level (thank you rectangular projection!).&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;zoom = 3&lt;/code&gt;, for example, &lt;code&gt;longitude_span.map_width/ ~= 0.175&lt;/code&gt; for any Google Map.&lt;/p&gt;
&lt;p&gt;Even more, for each increment in the zoom level, the longitude span is multiplied by &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Therefore, an easy formula can be created to compute the zoom for a map:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;zoom = 3 + log2(0.175 * map_width / longitude_span)&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Viewport optimization&lt;/h2&gt;
&lt;p&gt;The size of the static map&amp;#8217;s &lt;span class="caps"&gt;URL&lt;/span&gt; is limited to &lt;code&gt;2048&lt;/code&gt; characters. This means that we should strive not to put unused information in it. :)&lt;/p&gt;
&lt;p&gt;This is why I optimized the &lt;span class="caps"&gt;URL&lt;/span&gt; generation by including only the markers and the path segments that are actually visible in the current viewport and left out the others.&lt;/p&gt;
&lt;p&gt;Also, the algorithm starts by trying to include as much precision in the coordinates as appropriate for the zoom level, and decreases the precision if the resulting &lt;span class="caps"&gt;URL&lt;/span&gt; is too long.&lt;/p&gt;
&lt;h2&gt;Limitations&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;the map width and height are limited by the Static Maps &lt;span class="caps"&gt;API&lt;/span&gt; to &lt;code&gt;640&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;the &lt;span class="caps"&gt;URL&lt;/span&gt; size is limited to &lt;code&gt;2048&lt;/code&gt; characters.  This basically means that maps with complicated paths (such as those of Directions for long distances) cannot be made static as the &lt;span class="caps"&gt;URL&lt;/span&gt; would be too big.&lt;/li&gt;
	&lt;li&gt;the map type for the static map is the default one: roadmap. If you want a different kind of map, you can change the &lt;code&gt;maptype&lt;/code&gt; parameter from &lt;code&gt;roadmap&lt;/code&gt; to &lt;code&gt;satellite&lt;/code&gt;, &lt;code&gt;terrain&lt;/code&gt; or &lt;code&gt;hybrid&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;GMap_to_static is one of the most challenging and rewarding pet projects I created. Using nice algorithms and playing with logarithms reminds me of the high-school days. And being able to easily generate static maps is wonderful (and addictive, beware!).&lt;/p&gt;</content>
    </entry>
  
    
    <entry>
      <title>Heroku, S3, canvas and the Security Error of doom</title>
      <link href="http://dira.ro/2011/10/17/heroku-s3-canvas-and-the-security-error-of-doom" />
      <id>tag:dira.ro,2011-10-17:/2011/10/17/heroku-s3-canvas-and-the-security-error-of-doom</id>
      <updated>2011-10-17T12:17:14Z</updated>
      <content type="html">&lt;p&gt;Let&amp;#8217;s say you have a nice little project, involving Heroku, S3 and &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;. It works like a charm&amp;#8230; that is, until you need to do something totally crazy. Such as, stitching some of your images together in a canvas and uploading the result to your application. That should be easy, right? But&amp;#8230; browsers throw a security error when you do it, and you find out that you cannot access the data in a canvas that contains images loaded from a different domain.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;: In September 2012, Amazon added &lt;a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/cors.html"&gt;&lt;span class="caps"&gt;CORS&lt;/span&gt; support for S3&lt;/a&gt;. See &lt;a href="#cors"&gt;more about how this helps&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Enter postMessage&lt;/h2&gt;
&lt;p&gt;Cross-document messaging, represented by &lt;a href="https://developer.mozilla.org/en/DOM/window.postMessage"&gt;postMessage&lt;/a&gt;, a little-known hero of the browser world, comes to the rescue. It allows to send messages to other windows in the current browser, and receive messages (asynchronously). It &lt;a href="http://caniuse.com/#feat=x-doc-messaging"&gt;works&lt;/a&gt; in all modern browsers.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.websequencediagrams.com/cgi-bin/cdraw?lz=bWFpbl93aW5kb3ctPmFub3RoZXIACQc6IEhleSwgZXhhbXBsZS5jb20sIGFyZSB5b3UgdGhlcmU_Cm5vdGUgcmlnaHQgb2YgAC8QdGhpbmtpbmcgYWJvdXQgaXQKAFMOLT4Acws6IHllYWgKCg&amp;amp;s=roundgreen" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The sender specifies the recipient &lt;code&gt;&amp;lt;window&amp;gt;&lt;/code&gt; and &lt;strong&gt;domain&lt;/strong&gt;, and the message as a string. The receiver can see, for each message, from what &lt;strong&gt;domain&lt;/strong&gt; it comes, and take into account only the trusted ones.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.websequencediagrams.com/cgi-bin/cdraw?lz=dW50cnVzdGVkX3dpbmRvdy0-YW5vdGhlcgAJBzogSGV5LCBleGFtcGxlLmNvbSwgYXJlIHlvdSB0aGVyZT8Kbm90ZSByaWdodCBvZiAALxAAWAkuY29tIAAOIEkgZG9uJ3Qga25vdyB0aGlzIGRvbWFpbg&amp;amp;s=roundgreen" alt="" /&gt;&lt;/p&gt;
&lt;h2&gt;How does this help with image loading?&lt;/h2&gt;
&lt;p&gt;You create an &lt;strong&gt;&lt;span class="caps"&gt;HTML&lt;/span&gt;&lt;/strong&gt; file that will act as a proxy loader, and upload it on S3, next to the images. The proxy&amp;#8217;s job is to receive the &lt;span class="caps"&gt;URL&lt;/span&gt; of an image, and return that image serialized as a string.&lt;/p&gt;
&lt;p&gt;The application commands, via &lt;code&gt;postMessage&lt;/code&gt;: &lt;code&gt;"load /image_path"&lt;/code&gt;. The proxy, being on the same domain as the image, loads it without any restriction, and replies: &lt;code&gt;"loaded /image_path, here is it, serialized"&lt;/code&gt;. Now the application can create a new image from the serialization, and the image&amp;#8217;s origin will be the application&amp;#8217;s domain, not S3.&lt;/p&gt;
&lt;p&gt;The good news is, you don&amp;#8217;t have to create the proxy or image loading handlers by yourself. I already wrote that code so you can &lt;a href="http://github.com/dira/cross-domain-image-proxy"&gt;steal my shiny implementation&lt;/a&gt;. Check out &lt;a href="http://dira.ro/code/post-message-demo/"&gt;the live demo&lt;/a&gt; to see it in action.&lt;/p&gt;
&lt;h2 id="problem"&gt;More about the problem&lt;/h2&gt;
&lt;p&gt;You can include any image, from any domain, on your website with &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;. But when it comes to getting the pixels of an image from another domain &amp;#8211; for example, by putting it in a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; and calling &lt;code&gt;getImageData()&lt;/code&gt; or &lt;code&gt;getDataUrl()&lt;/code&gt;, browsers throw the Security Error because of the &lt;strong&gt;Same Origin policy&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is frustrating if the other domain is also yours. If you could just say, somehow, &amp;#8220;this image on S3 is mine, as well as example.com, let the site use the image&amp;#8221;.&lt;/p&gt;
&lt;p id="cors"&gt;That is exactly what the &lt;a href="http://www.w3.org/TR/cors/" title="CORS"&gt;Cross-origin resource sharing&lt;/a&gt; specification aims to fix. With &lt;span class="caps"&gt;CORS&lt;/span&gt;, the owner of the image grants access to the image to some domains, by setting certain &lt;span class="caps"&gt;HTTP&lt;/span&gt; headers. &lt;span class="caps"&gt;CORS&lt;/span&gt; has decent &lt;a href="http://caniuse.com/cors"&gt;browser support&lt;/a&gt;, &lt;del&gt;but unfortunately S3 does not allow setting the &lt;span class="caps"&gt;CORS&lt;/span&gt; &lt;span class="caps"&gt;HTTP&lt;/span&gt; headers and &lt;a href="https://forums.aws.amazon.com/thread.jspa?threadID=34281"&gt;does not plan&lt;/a&gt; to do it either.&lt;/del&gt; &lt;b&gt;Update&lt;/b&gt;: In September 2012, Amazon added &lt;a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/cors.html"&gt;&lt;span class="caps"&gt;CORS&lt;/span&gt; support for S3&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Other solutions&lt;/h2&gt;
&lt;p&gt;A common solution is to make a proxy on your server, relay all image requests to S3 and return the result. You can do it if you own &amp;amp; configure your server, but for a hobby project hosted on the free plan of Heroku it is not a good fit. When you have one dyno for the entire app, keeping it busy with relaying tens of images per board view is not acceptable.&lt;/p&gt;
&lt;p&gt;Another solution is to use a Flash proxy. Enough said.&lt;/p&gt;
&lt;p&gt;A third solution involves having a Javascript proxy hosted on S3. If the application is &lt;code&gt;tzigla.com&lt;/code&gt;, the S3 bucket would be aliased to &lt;code&gt;images.tzigla.com&lt;/code&gt;. The proxy would be loaded in a hidden iframe and it would load the images via Javascript. Then it would &lt;a href="https://developer.mozilla.org/En/DOM/Document.domain"&gt;declare&lt;/a&gt; that its domain is no longer &lt;code&gt;images.tzigla.com&lt;/code&gt;, but &lt;code&gt;tzigla.com&lt;/code&gt;. After that, it could communicate with all the javascript loaded form &lt;code&gt;tzigla.com&lt;/code&gt; and send it the images. The drawback is that after a batch of loading, the proxy cannot be used anymore (because it is not in the same domain as the images anymore).&lt;/p&gt;
&lt;p&gt;There is also &lt;a href="http://easyxdm.net/wp/"&gt;easyXDM&lt;/a&gt;, a library with the same purpose that covers all browsers using a combination of postMessage, Flash, the iframe url hash technique, providing an interface with Socket and &lt;span class="caps"&gt;RPC&lt;/span&gt; abstractions. But if you support modern browsers only, it is too much.&lt;/p&gt;
&lt;h2&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;postMessage&lt;/code&gt; saves the day and, with a few lines of code, you can get rid of the Same Origin Browser Security error. You can load your images from S3, process then in a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;, and then access the resulting pixels, save the canvas as an image, or whatever else you fancy.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve put the full working code for the &lt;a href="http://dira.ro/code/post-message-demo/"&gt;demo&lt;/a&gt; on &lt;a href="https://github.com/dira/cross-domain-image-proxy"&gt;github&lt;/a&gt;. Let me know if it helps you and, if you have any questions or suggestions, drop me a note to &lt;a href="http://twitter.com/dira_geek_girl"&gt;@dira_geek_girl&lt;/a&gt; on twitter.&lt;/p&gt;
&lt;h2&gt;P.S.&lt;/h2&gt;
&lt;p&gt;This code is extracted from &lt;a href="http://tzigla.com"&gt;Tzigla&lt;/a&gt;, a lovely collaborative art project with tiles and pixel art. You should definitely make some tiles there, it&amp;#8217;s pretty fun.&lt;/p&gt;</content>
    </entry>
  
    
    <entry>
      <title>OmniAuth strategy for everything else</title>
      <link href="http://dira.ro/2010/11/30/omniauth-strategy-for-everything-else" />
      <id>tag:dira.ro,2010-11-30:/2010/11/30/omniauth-strategy-for-everything-else</id>
      <updated>2010-11-30T12:24:22Z</updated>
      <content type="html">&lt;p&gt;
  &lt;a href='http://github.com/intridea/omniauth'&gt;OmniAuth&lt;/a&gt;
  makes it incredibly easy to authenticate users using an extensive list of external providers. But, what about using a provider that it does not support out of the box - let's say, a PHP forum?
&lt;/p&gt;
&lt;p&gt;I had to authenticate users from &lt;a href='http://www.wayofthepixel.net/'&gt;Pixelation&lt;/a&gt; into &lt;a href='http://tzigla.com/'&gt;Tzigla&lt;/a&gt;, a Rails app that already used OmniAuth with Facebook and Twitter. So, I wrote a custom OmniAuth strategy which, in collaboration with a tiny PHP script on the Pixelation server, made this possible.&lt;/p&gt;
&lt;p&gt;I'll first explain a bit about &lt;strong&gt;how OmniAuth works&lt;/strong&gt; and then I'll show you  the actual &lt;strong&gt;Pixelation authorization strategy&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;How OmniAuth works&lt;/h2&gt;
&lt;p&gt;OmniAuth assumes that any authorization process has two phases: &lt;strong&gt;request&lt;/strong&gt; and &lt;strong&gt;callback&lt;/strong&gt;. Here's the request dance of an authentication process:&lt;/p&gt;
&lt;img src='/images/resources/omni_auth.png' /&gt;
&lt;p&gt;The request is typically a redirect to the provider's website. The provider authenticates the user and (optionally) asks permission to share information about him with the application. Then the provider redirects again to our application, sending along data about the user.&lt;/p&gt;
&lt;p&gt;Looking more into detail, OmniAuth has two parts: the core library and &lt;strong&gt;strategies&lt;/strong&gt; for using various providers. Here's how strategies fit in the grand scheme of things:&lt;/p&gt;
&lt;img src='/images/resources/omni_auth_internal.png' /&gt;
&lt;p&gt;The core library intercepts all the authentication URLs, determines which is the strategy to use (based on the provider parameter in the URL), and then steps out of the way and lets the strategy decide what to do.&lt;/p&gt;
&lt;p&gt;This means that the Facebook strategy will redirect to a Facebook URL and expect, in the callback, data about the user in the format from the Facebook specification. Of course, the Twitter strategy will be different and act according the Twitter spec, and so on.&lt;/p&gt;
&lt;h2&gt;The Pixelation authorization strategy&lt;/h2&gt;
&lt;p&gt;Since OmniAuth is doing all the dirty work, we need to implement just a few things:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;redirect to the authentication URL on the Pixelation forum for the &lt;strong&gt;request phase&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;receive the user's id, username and avatar in the &lt;strong&gt;callback phase&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;be able to check that the callback comes from Pixelation and not from some identity thief.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, we have to configure our provider. We need &lt;strong&gt;a Pixelation URL for the request phase&lt;/strong&gt; and &lt;strong&gt;a shared secret&lt;/strong&gt; known only by our app and the Pixelation forum. At the callback phase, the data about the user will be signed by Pixelation with this secret.&lt;/p&gt;
&lt;p&gt;Like with all providers, we setup the parameters in a Rails initializer. Since we're not bundled with OmniAuth, we also need to autoload our class:&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;# config/initializers/omniauth.rb&amp;#x000A;module OmniAuth&amp;#x000A;  module Strategies&amp;#x000A;    # tell OmniAuth to load our strategy&amp;#x000A;    autoload :Pixelation, 'lib/pixelation_strategy'&amp;#x000A;  end&amp;#x000A;end&amp;#x000A;&amp;#x000A;Rails.application.config.middleware.use OmniAuth::Builder do&amp;#x000A;  provider :twitter, "app_name", "secret"&amp;#x000A;  provider :facebook, "app_name", "secret", :scope =&gt; ''&amp;#x000A;  # pass the 2 parameters to the constructor&amp;#x000A;  provider :pixelation, "secret", "redirect URL"&amp;#x000A;end&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;In the Pixelation strategy we save the received parameters&amp;hellip;&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;# receive parameters from the strategy declaration and save them&amp;#x000A;def initialize(app, secret, auth_redirect, options = {})&amp;#x000A;  @secret = secret&amp;#x000A;  @auth_redirect = auth_redirect&amp;#x000A;  super(app, :pixelation, options)&amp;#x000A;end&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;&amp;hellip;then use the redirect URL in the request phase&amp;hellip;&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;# redirect to the Pixelation website&amp;#x000A;def request_phase&amp;#x000A;  r = Rack::Response.new&amp;#x000A;  r.redirect @auth_redirect&amp;#x000A;  r.finish&amp;#x000A;end&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;&amp;hellip;and use the secret to verify the received data in the callback phase:&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;def callback_phase&amp;#x000A;  uid, username = request.params["uid"], request.params["username"]&amp;#x000A;  avatar, token = request.params["avatar"], request.params["token"]&amp;#x000A;  sha1 = Digest::SHA1.hexdigest("a mix of #{@secret}, #{uid}, #{username}, #{avatar}")&amp;#x000A;&amp;#x000A; # check if the request comes from Pixelation or not&amp;#x000A;  if sha1 == token&amp;#x000A;    @uid, @username, @avatar = uid, username, avatar&amp;#x000A;    super # OmniAuth takes care of the rest&amp;#x000A;  else&amp;#x000A;    fail!(:invalid_credentials) # OmniAuth takes care of the rest&amp;#x000A;  end&amp;#x000A;end&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;Check out the Pixelation class: &lt;a href='http://gist.github.com/722793'&gt;http://gist.github.com/722793&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Writing a new OmniAuth strategy was a lot easier than I expected. I hope that sharing my experience will help you better understand how OmniAuth works and how you can develop new strategies on top of it.&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>Huge background picker</title>
      <link href="http://dira.ro/2010/11/16/huge-background-picker" />
      <id>tag:dira.ro,2010-11-16:/2010/11/16/huge-background-picker</id>
      <updated>2010-11-16T12:17:30Z</updated>
      <content type="html">&lt;p&gt;I think it is impossible to choose a background color using a normal-size color picker. The color that you see in the tiny box seems perfect; and then, when applied to a big surface, it looks totally different.&lt;/p&gt;
&lt;p&gt;Say hello to &lt;a href="http://huge-background-picker.heroku.com/#d9b6be"&gt;huge background picker&lt;/a&gt;, a nice little app I wrote to solve this. Choose a color and you will see it the way you intend to use it &amp;#8211; as background.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://huge-background-picker.heroku.com/#ae92b0"&gt;&lt;img src="http://img.skitch.com/20101116-fc2fn3sptj5ua3crhsbjgumfd8.png" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;</content>
    </entry>
  
    
    <entry>
      <title>Stylish buttons - so easy with CSS3 and Sass</title>
      <link href="http://dira.ro/2010/10/30/stylish-buttons-so-easy-with-css3-and-sass" />
      <id>tag:dira.ro,2010-10-30:/2010/10/30/stylish-buttons-so-easy-with-css3-and-sass</id>
      <updated>2010-10-30T12:28:29Z</updated>
      <content type="html">&lt;p&gt;
  Yesterday I found the super yummy
  &lt;a href='http://www.webdesignerwall.com/demo/css-buttons.html'&gt;
    pure-CSS
  &lt;/a&gt;
  buttons designed by
  &lt;a href='http://www.webdesignerwall.com/tutorials/css3-gradient-buttons/'&gt;Web Designer Wall&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  Wondering how one could use this design wisdom despite not posessing the art of subtle gradients and matching colors, I created
  &lt;a href='http://css3-buttons.heroku.com/generator#DD2222'&gt;code&lt;/a&gt;
  that does this by magic. And by magic I mean
  &lt;a href='http://sass-lang.com/'&gt;Sass&lt;/a&gt;,
  its
  &lt;a href='http://nex-3.com/posts/89-powerful-color-manipulation-with-sass'&gt;color functions&lt;/a&gt;,
  and some formulas to derive the colors for gradients, border and text starting from the base color.
&lt;/p&gt;
&lt;p&gt;So now I can get these&lt;/p&gt;
&lt;p&gt;
  &lt;img alt='' src='http://img.skitch.com/20101103-p29k48p4pe8qcc7ukxf59qmpbf.png' /&gt;
&lt;/p&gt;
&lt;p&gt;… with this little code:&lt;/p&gt;
&lt;pre class='brush: sass'&gt;@import "_buttons"&amp;#x000A;&amp;#x000A;.button&amp;#x000A;  +button&amp;#x000A;  +color(#d22)&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;
  Go to the
  &lt;a href='/code/CSS3-buttons/'&gt;project’s page&lt;/a&gt;
  for the
  &lt;a href='/code/CSS3-buttons/'&gt;full description and the mixin&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  Or, if you don’t fancy Sass (although you should), I created a page to
  &lt;a href='http://css3-buttons.heroku.com/generator'&gt;
    generate the
    &lt;span class='caps'&gt;CSS&lt;/span&gt;
  &lt;/a&gt;
  for yummy buttons in the color of your choosing.
&lt;/p&gt;
&lt;p&gt;
  April 2013:
  &lt;a href='https://gist.github.com/adamjohnson/5155252'&gt;SCSS with compass implementation&lt;/a&gt;
  by Adam Johnson
&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>Fixed bugs for fun. Rails BugMash</title>
      <link href="http://dira.ro/2009/08/14/will-fix-bugs-for-fun-rails-bugmash" />
      <id>tag:dira.ro,2009-08-14:/2009/08/14/will-fix-bugs-for-fun-rails-bugmash</id>
      <updated>2009-08-14T12:15:18Z</updated>
      <content type="html">&lt;p&gt;Last weekend I took part in &lt;a href="http://railsbridge.org/news_items/4"&gt;Rails BugMash&lt;/a&gt; &amp;#8211; a &amp;#8216;bug squashing&amp;#8217; event organized by RailsBridge.&lt;/p&gt;

&lt;p&gt;From the beginning I found some ActiveRecord issues that seemed very interesting. What I learned is that digging through ActiveRecord is a lot easier in concept than through source code. Therefore, I managed to produce only a partial patch. The bright side is that it was a lot easier with tests, so I was more productive on this side.&lt;/p&gt;

&lt;p&gt;Even if it didn&amp;#8217;t add many points on my &lt;a href="http://bugmash.heroku.com/participants/33"&gt;scorecard&lt;/a&gt;, the &amp;#8220;ActiveRecord adventure&amp;#8221; was indeed very interesting. Here are some useful tips for ActiveRecord testing:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;recreate the tables after changing the schema: you have to do it yourself if running a single ActiveRecord test&lt;/p&gt;
    &lt;pre class='brush: ruby'&gt;
# update the schema
rake test_mysql TEST=test/cases/aaa_create_tables_test.rb
# run a specific test
rake test_mysql TEST=test/cases/associations/has_many_through_associations_test.rb

# this will create the tables
rake test_mysql
  &lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;looking for the SQL generated during a test? &lt;code&gt;activerecord/debug.log&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
  &lt;p&gt;verify if an associated object is loaded? The way to do it depends on the realation type:&lt;/p&gt;
  &lt;pre class='brush: ruby'&gt;
# Cat has_many Toys. Are they loaded?
cat.toys.loaded? # false
cat.toys
cat.toys.loaded? # true

# Cat belongs_to Human. Is it loaded?
cat.instance_variable_get('@human').present? # false
cat.human
cat.instance_variable_get('@human').present? # true
  &lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;adding an ActiveRecord test? it&amp;#8217;s preferred to reuse the existing models rather than create new ones. Even if &lt;a href="http://github.com/rails/rails/blob/6f5d1f31907be5ff514c61bed9dc776eb3e5b76a/activerecord/test/models/author.rb"&gt;some models&lt;/a&gt; look a bit abused after so much use :), I guess it&amp;#8217;s better than having a couple of new models for every patch&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was impressed by the energy and collaboration in the (virtual) room: issue creation, verification, testing &amp;amp; patching seemed to flow from person to person. This meant that I got feedback fast on my contributions, which was great.&lt;/p&gt;

&lt;p&gt;Big Kudos to RailsBridge for organizing the event and easing the &amp;#8216;contributing to Rails learning curve&amp;#8217;. It allowed me to use my Ruby &amp;amp; Rails skills to the max, even if it was the first time I contributed.&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>Back from Euruko 2009</title>
      <link href="http://dira.ro/2009/05/12/back-from-euruko-2009" />
      <id>tag:dira.ro,2009-05-12:/2009/05/12/back-from-euruko-2009</id>
      <updated>2009-05-12T12:11:10Z</updated>
      <content type="html">&lt;p&gt;Euruko &amp;#8211; the European Ruby conference &amp;#8211; was in Barcelona this year. It was a blend of &lt;a href="http://www.flickr.com/photos/zanaguara/sets/72157617899159197/"&gt;enthusiastic community&lt;/a&gt; and &lt;a href="http://app.euruko2009.org/talks"&gt;interesting talks&lt;/a&gt;, in two intense days, facilitated by wonderful organization.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://euruko2009.org/images/cover.png"/&gt;&lt;/p&gt;
&lt;p&gt;Besides language/programming-oriented talks, there was an abundance of &lt;a href="http://app.euruko2009.org/talks"&gt;presentations&lt;/a&gt; about what you can do with ruby in various fields: games programming, image processing, system configuration automation, voip, mobile apps, music.&lt;/p&gt;
&lt;p&gt;The lightning talks sessions were very popular &amp;#8211; the 5 minutes format (and the terrifying gong sound) was &amp;#8216;fast &amp;amp; furious&amp;#8217; &amp;#8211; and the information overload was appreciated.&lt;/p&gt;
&lt;a title="IMG_5048 by Emili Parreño, on Flickr" href="http://www.flickr.com/photos/eparreno/3518247908/"&gt;&lt;img style="margin-left: 10px; margin-right: 10px;" src="http://farm4.static.flickr.com/3653/3518247908_003a033aff.jpg" alt="IMG_5048" width="240" height="160" /&gt;&lt;/a&gt;foto by Emili Parreño
&lt;p&gt;I had a lightning talk about &lt;a href="http://github.com/dira/vimmish/tree/master"&gt;vimmish&lt;/a&gt; &amp;#8211; presented what it can do and what I am working on now: generating random vim command strings, based on the grammar.&lt;/p&gt;
&lt;p&gt;When I got to the part about parsing the vimmish grammar itself using &lt;a href="http://treetop.rubyforge.org/"&gt;treetop&lt;/a&gt;&amp;#8217;s meta-grammar half of the audience was giving me facial hints that I did not explain that well enough (well, I had 5 minutes for all the talk.. :) ). But everyone understood what I meant when I got to the examples &amp;#8211; randomly generated &lt;a href="http://www.polygen.org/it/grammatiche/musica_cinema_e_spettacolo/eng/metal.grm"&gt;metal band names&lt;/a&gt; and &lt;a href="http://www.polygen.org/it/grammatiche/tecnologie/eng/manager.grm"&gt;manager speeches&lt;/a&gt; from the crazy italian site &lt;a href="http://www.polygen.org/it"&gt;polygen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some people told me it was the geekiest lightning talk of the first day &amp;#8211; not sure whether it was the topic, the fact that I delivered the presentation as a sequence tabs in firefox (don&amp;#8217;t ever do that, you&amp;#8217;ll mess the ctrl-tab under the merciless spotlights. twice.) or the polygen examples, or their effect combined :).&lt;/p&gt;
&lt;object width="425" height="355" data="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=vimmish-090513060511-phpapp02&amp;amp;rel=0&amp;amp;stripped_title=vimmish" type="application/x-shockwave-flash"&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=vimmish-090513060511-phpapp02&amp;amp;rel=0&amp;amp;stripped_title=vimmish" /&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;/object&gt;
&lt;p&gt;Next year, Euruko will be in Kraków, Poland &amp;#8211; there were more than 20 polish developers this year and they were very enthusiastic about the conference. So, see everybody again next year, in Poland!&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>vimmish - vim translator</title>
      <link href="http://dira.ro/2009/05/07/vimmish-vim-translator" />
      <id>tag:dira.ro,2009-05-07:/2009/05/07/vimmish-vim-translator</id>
      <updated>2009-05-07T12:31:18Z</updated>
      <content type="html">&lt;p&gt;
  &lt;a href='http://github.com/dira/vimmish/tree/master'&gt;Vimmish&lt;/a&gt;
  is a translator from
  &lt;a href='http://www.vim.org/htmldoc/usr_03.html'&gt;VIM cryptic commands&lt;/a&gt;
  to human-readable explanations. I built it using a
  &lt;a href='http://en.wikipedia.org/wiki/Parsing_expression_grammar'&gt;parsing expression grammar&lt;/a&gt;
  the wonderful
  &lt;a href='http://treetop.rubyforge.org/'&gt;Treetop&lt;/a&gt;
  library.
&lt;/p&gt;
&lt;p&gt;
  So, you can feed
  &lt;a href='http://github.com/dira/vimmish/tree/master'&gt;vimmish&lt;/a&gt;
  with a sequence of commands that you got from a cryptic guru, and it will tell you what it means.
&lt;/p&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;p&gt;Input:&lt;/p&gt;
&lt;code&gt;iDon't know vim :(.&amp;lt;ESC&gt;^2WBc2wbetter now&amp;lt;ESC&gt;&amp;lt;RIGHT&gt;Da.&amp;lt;ESC&gt;II can understan&amp;lt;ESC&gt;&amp;lt;RIGHT&gt;~dE&lt;/code&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                  i =&gt; insert before cursor:&amp;#x000A; Don't know vim :(. =&gt; type Don't know vim :(.&amp;#x000A;              &amp;lt;ESC&gt; =&gt; go to normal mode&amp;#x000A;                  ^ =&gt; move to the begining of the line (not blank character)&amp;#x000A;                 2W =&gt; move to the begining of the next space-separated word, 2 times&amp;#x000A;                  B =&gt; move backwards one space-separated-word&amp;#x000A;                c2w =&gt; change to the begining of the next word, 2 times&amp;#x000A;         better now =&gt; type better now&amp;#x000A;              &amp;lt;ESC&gt; =&gt; go to normal mode&amp;#x000A;            &amp;lt;RIGHT&gt; =&gt; move one character to the right&amp;#x000A;                  D =&gt; delete the rest of the current line&amp;#x000A;                  a =&gt; append after cursor:&amp;#x000A;                  . =&gt; type .&amp;#x000A;              &amp;lt;ESC&gt; =&gt; go to normal mode&amp;#x000A;                  I =&gt; insert to the begining of the current line:&amp;#x000A;    I can understan =&gt; type I can understan&amp;#x000A;              &amp;lt;ESC&gt; =&gt; go to normal mode&amp;#x000A;            &amp;lt;RIGHT&gt; =&gt; move one character to the right&amp;#x000A;                  ~ =&gt; change character case&amp;#x000A;                 dE =&gt; delete to the end of the next space-separated-word&amp;#x000A;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool! Now all that gibberish makes sense!&lt;/p&gt;
&lt;p&gt;
  small-print disclaimer: while vimmish doesn
  t cover (yet) all the possible commands, it is fairly powerful as it understands
  &lt;a href='http://github.com/dira/vimmish/blob/37c8f73ac35c3c2bd17fa7eeedaf6ab269994b1e/test_results.txt'&gt;a lot of them&lt;/a&gt;
  (and combinations).
&lt;/p&gt;
&lt;h2&gt;And what about these grammars...&lt;/h2&gt;
&lt;p&gt;
  If you
  re new to grammars, you can think of them as regular expressions taken to the next level. That is, with power to express more things.
&lt;/p&gt;
&lt;p&gt;
  For example, with a regular expression you could search for all lines in a file that end with
  &lt;code&gt;;&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;/.*;$/&lt;/pre&gt;
&lt;p&gt;But you cannot build a regular expression that will tell you if a sequence of text is formed from parenthesis that are closed correctly (no one missing, no one extra, no one closed if there was not a corresponding opening one.. you get the idea). But you could do that with a grammar:&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;grammar OnlyParenthesis&amp;#x000A;  rule parenthesis_sequence&amp;#x000A;    ''&amp;#x000A;    /&amp;#x000A;    '(' parenthesis_sequence ')'&amp;#x000A;  end&amp;#x000A;end&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;
  The
  &lt;code&gt;/&lt;/code&gt;
  operator means
  &lt;code&gt;or&lt;/code&gt;.
  So a parenthesis_sequence is either an empty string or a pair of parenthesis that contains another parenthesis_sequence.  This recursion is, of course, one of the key powers of grammars.
&lt;/p&gt;
&lt;p&gt;
  So according to this grammar,
  &lt;code&gt;&amp;nbsp;&lt;/code&gt;
  is correct, so is
  &lt;code&gt;()&lt;/code&gt;,
  and so is
  &lt;code&gt;(())&lt;/code&gt;
  - it has a pair of parenthesis () that contain a string that matches the rule. But
  &lt;code&gt;())&lt;/code&gt;
  is not correct as the outer parenthesis do not contain a correct sequence.
&lt;/p&gt;
&lt;p&gt;
  Having a grammar that defines acceptable texts - that is, a language - you can build a parser that verifies whether a given string belongs to that language or not. This is exactly what the
  &lt;a href='http://treetop.rubyforge.org'&gt;Treetop&lt;/a&gt;
  library offers.
&lt;/p&gt;
&lt;p&gt;
  And.. what are grammars *really* useful for? Defining &amp; parsing complex languages - think DSLs. Or, parsing vim commands :D
  &lt;a href='http://github.com/dira/vimmish/blob/37c8f73ac35c3c2bd17fa7eeedaf6ab269994b1e/lib/grammar/vim.treetop'&gt;See the grammar&lt;/a&gt;.
&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>Deploying a non-trivial app on Heroku</title>
      <link href="http://dira.ro/2009/05/05/deploying-a-non-trivial-app-on-heroku" />
      <id>tag:dira.ro,2009-05-05:/2009/05/05/deploying-a-non-trivial-app-on-heroku</id>
      <updated>2009-05-05T12:13:14Z</updated>
      <content type="html">&lt;p&gt;I tried &lt;a href="http://heroku.com/"&gt;heroku&lt;/a&gt; &amp;#8211; the &amp;#8216;instant ruby platform&amp;#8217; for one of my pet projects. The deploy was indeed very fast &amp;#8211; less than 20 minutes from 0 to working app, but with a few glitches for advanced features.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Heroku does &lt;strong&gt;not give you bash access&lt;/strong&gt;, instead you have a &lt;a href="http://docs.heroku.com/console-rake"&gt;bunch of commands&lt;/a&gt; that cover all common tasks. You can use it as a script/console (that runs on your server) and to run rake tasks. Together with the admin functions available on the website, it covered everything that I needed.&lt;/p&gt;
    &lt;p&gt;Installing the app and getting the web part to work, with the db data from my local application, was a breeze; less than 20 minutes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Heroku is tightly integrated with git &amp;#8211; so whenever you &lt;strong&gt;push to your heroku git repository, the code is deployed&lt;/strong&gt;. Live. Automatically :) Your gems will be installed, code updated, and if everything is ok the web server will be restarted.&lt;/p&gt;
    &lt;p&gt;But &lt;strong&gt;you have to migrate the database yourself&lt;/strong&gt;. This was not obvious for me so I had 2 minutes of downtime until figuring it out. It would have been nice to run db:migrate automatically, but I guess that is too much of a semantic stretch for a git push.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;p&gt;The &lt;a href="http://heroku.com/how/architecture"&gt;architecture looks awesome&lt;/a&gt;. Grid, cloud, mash &amp;#8211; you name it, they have it, with &amp;#8216;high-performance&amp;#8217; adornment.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;Heroku specifics:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;you have to &lt;a href="http://docs.heroku.com/gems"&gt;declare the gems&lt;/a&gt; that you need in a gem manifest (if they are not &lt;a href="http://docs.heroku.com/technologies#installed-gems"&gt;already available&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;they propose using heroku config vars for storing your configuration variables instead of putting them in source. As you don&amp;#8217;t have direct access to the file system, you cannot create the config file when deploying; in fact, after deploy you can create files only in /tmp and /log. So, you have to choose between adding config files to git or using heroku config vars.&lt;/p&gt;
      &lt;p&gt;I decided not to hook into heroku too much while trying the platform, so I just added the config data to source.&lt;/p&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You setup your cron jobs by having a &lt;a href="http://docs.heroku.com/cron"&gt;rake task &lt;/a&gt;that will be run, in theory, once per hour. And you also have logs for your cron jobs.&lt;/p&gt;
    &lt;p&gt;However, &lt;strong&gt;the logs don&amp;#8217;t contain the error stream&lt;/strong&gt; &amp;#8211; just the output stream. This can be quite frustrating when trying to understand why the cron jobs don&amp;#8217;t seem to be running on the server.&lt;/p&gt;
    &lt;p&gt;In my case, I discovered that a config file was missing, after running the dedicated console command (heroku rake cron) and got the error message.&lt;/p&gt;&lt;/li&gt;
    &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Major glitch: lack of support&lt;/strong&gt;&lt;/p&gt;
    &lt;p&gt;My cron jobs still don&amp;#8217;t seem to be running; however, if I invoke the cron manually, it works. It could be because the operation in the cron takes around 30 seconds to complete, it could be something else.&lt;/p&gt;
    &lt;p&gt;However, I got no response on the support email about this problem since I asked, a week ago; other users &lt;a href="http://blog.heroku.com/archives/2009/4/24/commercial_launch/#comment-8647755"&gt;express the same concerns&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, it was an extremely pleasant experience for deploying the rails &amp;#8216;pure web&amp;#8217; part. Hopefully, when rolling the &lt;a href="http://blog.heroku.com/archives/2009/4/24/commercial_launch/"&gt;commercial version&lt;/a&gt; there will be some support.&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>GMaps stub released</title>
      <link href="http://dira.ro/2009/04/15/gmaps-stub-released" />
      <id>tag:dira.ro,2009-04-15:/2009/04/15/gmaps-stub-released</id>
      <updated>2009-04-15T12:16:22Z</updated>
      <content type="html">&lt;p&gt;As the load time for a Google Map (less than 2 seconds :)) &lt;a href="http://www.dira.ro/blog/2009/04/new-friends-new-enemies/"&gt;was hurting me&lt;/a&gt;, I retaliated by stubbing it.. The stub defines the same classes and functions as the GMaps JS API (not all of them :)),  returns some fake data when needed and plays dumb for the rest.&lt;/p&gt;
&lt;p&gt;This is enough for the rest of the Javascript to work and saves a couple of seconds on every page while developing or working on the UI.&lt;/p&gt;
&lt;p&gt;The code is available at &lt;a href="http://github.com/dira/gmaps-stub"&gt;http://github.com/dira/gmaps-stub&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>New friends, new enemies</title>
      <link href="http://dira.ro/2009/04/03/new-friends-new-enemies" />
      <id>tag:dira.ro,2009-04-03:/2009/04/03/new-friends-new-enemies</id>
      <updated>2009-04-03T12:23:14Z</updated>
      <content type="html">&lt;p&gt;
  &lt;a href='http://www.flickr.com/photos/tags/wurbe18'&gt;web geek&amp;#8217;s (un)conference&lt;/a&gt;
  in Bucharest was about
  &lt;a href='http://www.randsinrepose.com/archives/2008/04/21/saving_seconds.html'&gt;saving seconds&lt;/a&gt;&lt;span&gt;.&amp;nbsp;&lt;/span&gt;The talks were about improving all those little things that you do often and, even if the duration of each one has a magnitude of seconds or less, overall they
  &lt;strong&gt;eat your time&lt;/strong&gt;
  &amp;#8211; and sometimes your
  &lt;strong&gt;brains&lt;/strong&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So after giving more timeslots to the thread that was monitoring by keystrokes and neuron anxiety, i got:&lt;/p&gt;
&lt;h2&gt;2 new friends&lt;/h2&gt;
&lt;p&gt;
  Meet
  &lt;strong&gt;jack&lt;/strong&gt;
  and
  &lt;strong&gt;sack&lt;/strong&gt;
  &amp;#8211; the time saviors:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ack&amp;#x000A;alias ack="ack-grep -i -a"&amp;#x000A;jack() {&amp;#x000A;  ack $1 --ignore-dir=vendor --ignore-dir=cache --ignore-dir=stubs public/javascripts&amp;#x000A;}&amp;#x000A;sack() {&amp;#x000A;  ack $1 public/stylesheets/sass&amp;#x000A;}&amp;#x000A;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  &lt;strong&gt;jack&lt;/strong&gt;
  searches through the javascript files &amp;#8211; that&amp;#8217;s everyting in
  &lt;code&gt;/public/javascript&lt;/code&gt;
  excluding libraries (
  &lt;code&gt;/vendor&lt;/code&gt;
  ) and the folder with all the js&amp;#8217;s compacted and and cached (
  &lt;code&gt;/cache&lt;/code&gt;
  ). So that&amp;#8217;s
&lt;/p&gt;
&lt;code&gt;jack searched_stuff&lt;/code&gt;
&lt;p&gt;instead of&lt;/p&gt;
&lt;code&gt;ack-grep  -i -a --ignore-dir vendor --ignore-dir cache --ignore-dir stubs searched_stuff public/javascripts&lt;/code&gt;
&lt;p&gt;I rely on jack for finding things like &amp;#8216;where is this method called&amp;#8217;, &amp;#8216;who listens to this event&amp;#8217; and &amp;#8216;is this CSS identifier/class used just for formatting or is the javascript referecing it too?&amp;#8217;.&lt;/p&gt;
&lt;p&gt;
  &lt;strong&gt;sack&lt;/strong&gt;
  is the little brother that does the same kind of search in the Sass files. The gain: that I don&amp;#8217;t have to type the
  &lt;code&gt;/public/stylesheets/sass&lt;/code&gt;
  path anymore.
&lt;/p&gt;
&lt;h2&gt;2 new enemies&lt;/h2&gt;
&lt;p&gt;The new &amp;#8220;enemies&amp;#8221; are external services that I didn&amp;#8217;t need during development, and that annoyed me in one way or another. No more!&lt;/p&gt;
&lt;p&gt;
  &lt;strong&gt;gmaps.&lt;/strong&gt;
  GMaps is a central part of
  &lt;a href='http://symbolya.com'&gt;symbolya&lt;/a&gt;
  ; while it is by no means slow, it still consumes a couple of seconds on every load. That can be most annoying (read: brain-power eater) when I am working on the pages that include the map, but I am changing or testing something else.
&lt;/p&gt;
&lt;p&gt;Solution: stub it!&lt;/p&gt;
&lt;p&gt;
  I created a dedicated environment, in which the real GMaps js is replaced with
  &lt;a href='http://github.com/dira/gmaps-stub'&gt;&lt;/a&gt;
  a local stub that creates classes with the same names as the ones we use from GMaps,  returns some fake data when needed and plays dumb for the rest.
&lt;/p&gt;
&lt;p&gt;
  Time saved: 2-3 seconds/per page load. Brain power: priceless.
&lt;/p&gt;
&lt;p&gt;
  &lt;strong&gt;crowdsound&lt;/strong&gt;&lt;span&gt;.&amp;nbsp;&lt;/span&gt;Including crowdsound leads to a JS error and the nice red error icon in Firebug made my brain freak out every time I saw it. That is, every time I was looking at the site during development.
&lt;/p&gt;
&lt;p&gt;Solution: remove it from the development environment(s) &amp;#8211; where it is not used anyway. No more brain panic ftw!&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>Friendly URLs - reverberations</title>
      <link href="http://dira.ro/2009/03/02/friendly-urls-reverberations" />
      <id>tag:dira.ro,2009-03-02:/2009/03/02/friendly-urls-reverberations</id>
      <updated>2009-03-02T12:15:27Z</updated>
      <content type="html">&lt;p&gt;
  Friendly URLs contain human-parseable meaning. Like
  &lt;code&gt;contributors/dira&lt;/code&gt;
  instead of
  &lt;code&gt;users/2&lt;/code&gt;
  (ok, for some humans the second route conveys a lot of meaning too :D).
&lt;/p&gt;
&lt;p&gt;They are desirable in many situations, but what is the cost? The change is  facilitated by Rails; however, depending on the amplitude of the change, there can be more or less reverberations throughout your application.&lt;/p&gt;
&lt;h2&gt;Change route name&lt;/h2&gt;
&lt;p&gt;
  &lt;code&gt;posts/1&lt;/code&gt;  becomes  
    &lt;code&gt;articles/1&lt;/code&gt;.
  Reverberations: none
&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;# change name for generated routes&amp;#x000A;map.resources :posts, :as =&gt; 'articles'&amp;#x000A;&amp;#x000A;# manually update any custom routes that use the old name&amp;#x000A;map.post_draft '/article/:id/:token', :controller =&gt; 'posts',&amp;#x000A;        :action =&gt; 'show', :conditions =&gt; { :method =&gt; :get }&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;The controller/integration tests still work, the application works, everybody go home.&lt;/p&gt;
&lt;h2&gt;Change route parameters&lt;/h2&gt;
&lt;p&gt;
  &lt;code&gt;users/1&lt;/code&gt;
  becomes  
  &lt;code&gt;users/dira&lt;/code&gt;.
  Reverberations: more
&lt;/p&gt;
&lt;p&gt;First, decide what field from your model to show in the URL.  Then:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;
      if you already have a property perfectly suitable to be an URL (contains only alpha-numerical characters,
      &lt;strong&gt;no slashes or dots&lt;/strong&gt;),
      and that is already unique among existing records. Assuming it's the
      &lt;code&gt;login&lt;/code&gt;
      field of the User model:
    &lt;/p&gt;
    &lt;pre class='brush: ruby'&gt;# model:&amp;#x000A;def to_param&amp;#x000A; login.parameterize&amp;#x000A;end&amp;#x000A;&amp;#x000A;# for controllers (the User controller and all the controllers that are&amp;#x000A;# nested under it, or in other namespaces): replace User.find(params[:id]) with&amp;#x000A;User.find_by_login(params[:id])&amp;#x000A;&lt;/pre&gt;
    &lt;p&gt;
      If using
      &lt;a href='http://mr.hamptoncatlin.com/'&gt;make_resourceful&lt;/a&gt;
      or another plugin for resourceful controllers, add a method that retrieves the needed object by login instead of by id:
    &lt;/p&gt;
    &lt;pre class='brush: ruby'&gt;def current_object&amp;#x000A;  User.find_by_login(params[:id])&amp;#x000A;end&amp;#x000A;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      otherwise, use a plugin like
      &lt;a href='http://github.com/technoweenie/permalink_fu'&gt;permalink_fu&lt;/a&gt;
      or
      &lt;a href='http://github.com/schof/find_by_param/'&gt;find_by_param&lt;/a&gt;
      to take care of transforming your data into a URL-compatible value, assuring that it is unique etc. For using the
      &lt;code&gt;login&lt;/code&gt;
      field again, the changes are:
    &lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;define a column in the database (default name: permalink)&lt;/li&gt;
      &lt;li&gt;create a migration in which you set the permalink value (using the functions offered by the plugin) for the data already created&lt;/li&gt;
      &lt;li&gt;define the permalink in the model&lt;/li&gt;
      &lt;li&gt;adjust the controllers to retrieve resources based on the permalink, not the id&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    there is
    &lt;a href='http://snippets.dzone.com/posts/show/4376'&gt;a quick and dirty option&lt;/a&gt;,
    for resources whose desired names are generally URL-compatible, but they could contain dots. The code prevents the dot to be interpreted as the separator in
    &lt;code&gt;/controller/resource.format&lt;/code&gt;.
    But I considering solution 2.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What about controller/integration tests?&lt;/p&gt;
&lt;pre class='brush: ruby'&gt;# if you used the more general&amp;#x000A;get :edit, :id =&gt; @user.to_param&amp;#x000A;&amp;#x000A;# instead of the specific&amp;#x000A;# get :edit, :id =&gt; @user.id&amp;#x000A;&lt;/pre&gt;
&lt;p&gt;your tests still work as nothing changed.&lt;/p&gt;
&lt;h2&gt;After that...&lt;/h2&gt;
&lt;p&gt;Using Ajax? check your Javascript files for connections to the old route name / parameters! Ack is your friend here.&lt;/p&gt;
&lt;p&gt;
  Not sure you got all the reverberations covered? You can use a tool like
  &lt;a href='http://github.com/relevance/tarantula'&gt;tarantula&lt;/a&gt;
  to spider your site and check that all the links are still working.
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    to benefit from its brute power, you should fill all your models with data before letting it crawl over it.
    &lt;br /&gt;
    If you're using fixtures, just load them in the tests as shown in tarantula's readme.
    &lt;br /&gt;
    If using factories, instantiate them so that you have content in the pages and tarantula can browse happily
  &lt;/li&gt;
  &lt;li&gt;
    are you using Javascript without
    &lt;a href='http://en.wikipedia.org/wiki/Progressive_Enhancement'&gt;progressive enhancement&lt;/a&gt;?
    tarantula will detect it and kill u :D
  &lt;/li&gt;
  &lt;li&gt;using namespaces? you can do separate tests in which you tell tarantula to crawl in each namespace (for example one test for public, one for admin). The report will contain a section for each test method&lt;/li&gt;
  &lt;li&gt;The one thing I didn't figure out with tarantula is how to prevent deleting a resource and then trying other actions on it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;In conclusion&lt;/h2&gt;
&lt;p&gt;Humanizing routes is not difficult but still there are some points to pay attention to. Using a permalink plugin and having well-written tests helps.&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>2012 at a glance</title>
      <link href="http://dira.ro/2013/04/03/2012-at-a-glance" />
      <id>tag:dira.ro,2013-04-03:/2013/04/03/2012-at-a-glance</id>
      <updated>2013-04-03T12:-37:-39Z</updated>
      <content type="html">&lt;h2&gt;Work&lt;/h2&gt;

&lt;p&gt;In the first 9 months of the year I worked with an american company in the health industry, developing a custom CMS tailored to their specific needs. It was an interesting project from which I learned a lot on a wide range of topics, from Rails specifics to using MongoDB to store a hierarchy of document types, smartly indexing data with ElasticSearch allowing for flexible searches, integrating video processing services, generating PDF's from html pages or customizing the CK Editor.&lt;/p&gt;

&lt;p&gt;In October a startup company asked me to integrate my &lt;a href="/2011/10/17/heroku-s3-canvas-and-the-security-error-of-doom"&gt;open source S3 proxy&lt;/a&gt; in their rich single-page application. I continued working with them, developing new features. I led the team in refactoring the application to apply MVC better, use Backbone effectively and simplify the code.&lt;/p&gt;

&lt;h2&gt;Conferences&lt;/h2&gt;

&lt;p&gt;Enjoyed the pink, bubbly &lt;a href="http://www.railsberry.com/2012"&gt;Railsberry&lt;/a&gt; conference in April. Lots of interesting talks, met old friends and got to know new interesting people. Gave a lightning talk about &lt;a href="http://tzigla.com/"&gt;tzigla&lt;/a&gt;, about the fun of personal projects and pixel drawings.&lt;/p&gt;

&lt;p&gt;While in Cracow I also took part in &lt;a href="http://hackkrk.tumblr.com/post/21022178014/hackkrk-4-super-social-night"&gt;hackkrk #4&lt;/a&gt;. There was speed dating, where I shared some ElasticSearch wisdom, and learned some cool command-line tricks. On the code retreat I paired with two Java developers; one important lesson was that none of us had a simple project setup ready and that wasted a lot of time.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.euruko2012.org/"&gt;Euruko&lt;/a&gt; started with a hackday, in which I teamed with a group of german developers and tried to fix a mongoid bug. Learned that we heavily depend on the internet for our work; that the bug was fixed a couple of days before; and how to use &lt;code&gt;git bisect&lt;/code&gt; to find which commit changed something in the repo (in our case, which commit fixed the bug). Also found out about &lt;a href="https://github.com/jfirebaugh/konacha"&gt;konacha&lt;/a&gt; as an alternative for &lt;a href="https://github.com/netzpirat/guard-jasmine"&gt;Guard::Jasmine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://2012.eurucamp.org/"&gt;Eurucamp&lt;/a&gt; was a mix of interesting workshops, interesting talks - from practical command line tools and scripts to more general best practices. There was plenty of time for socializing and I enjoyed talking to people about ruby, single page apps, and contracting.&lt;/p&gt;

&lt;p&gt;While in Berlin I gave a &lt;a href="http://dira.github.com/js-testing-presentation/"&gt;talk on javascript testing&lt;/a&gt; at the Berlin Javascript Applications Meetup. It was very well received and a lot of people had questions about the tools and processes they should use to introduce testing to their JS projects. I actually wrote a &lt;a href="https://github.com/dira/js-testing-presentation"&gt;test-driven Node app&lt;/a&gt; that takes a markdown presentation and creates a web page with the contents - which are about testing JS code. Meta is fun!&lt;/p&gt;

&lt;p&gt;In September I volunteered as a couch for &lt;a href="http://vimeo.com/51511255"&gt;Railsgirls Cologne&lt;/a&gt;. I enjoyed explaining Ruby, Rails, developing web applications and the ecosystem of tools and systems involved, and seeing 'my' girls learning, and tinkering with the application. Memorable takeaway: one attendee said 'done? the app is never done'. There's always room for progress, for improving 'the app', your skills, your life.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://12.rupy.eu/"&gt;Rupy&lt;/a&gt; was very dynamic, with short talks on two different tracks. Lots of different subjects, ideas, problems seen from different angles: modularization and decoupling in JS and Rails, AngularJS, command line tips, abstracting production, API design, scaling and availability.&lt;/p&gt;
</content>
    </entry>
  
    
    <entry>
      <title>The Robot Game at RailsGirls Krakow</title>
      <link href="http://dira.ro/2013/04/29/the-robot-game-at-railsgirls-krakow" />
      <id>tag:dira.ro,2013-04-29:/2013/04/29/the-robot-game-at-railsgirls-krakow</id>
      <updated>2013-04-29T12:29:17Z</updated>
      <content type="html">&lt;p&gt;I think it is hard to introduce people to programming by having theoretical presentations about code, commands, terminals &amp;amp; servers. That's why during &lt;a href="http://railsgirls.com/krakow2013"&gt;Railsgirls Krakow&lt;/a&gt; I organized a game that allows participants to experience, in real life, a lot of programming concepts.&lt;/p&gt;

&lt;h2&gt;The game&lt;/h2&gt;

&lt;p&gt;The goal is to drive the 'robot' through a maze, by giving it a sequence of commands, and have it bring back an object. At Railsgirls, some of the coaches played robots, and the objective was to make the robot reach a cupcake placed in the maze.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.facebook.com/photo.php?fbid=384861898294745&amp;amp;set=a.383039768476958.1073741837.350907338356868&amp;amp;type=3&amp;amp;theater"&gt;&lt;img src="/images/RailsGirls/robots%20at%20work.jpg" alt="Robots at work" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I love about this game is that, by playing it, one gets a lot about how programming works.&lt;/p&gt;

&lt;p&gt;The robots accepted instructions only when written on a piece of paper, and did not respond to any other interaction - just like machines run programs. We emphasized that the instructions in the program must have a specific structure - one command per line, and that the commands must belong to the set of available commands. Robots would 'error' in funny ways if the program wasn't valid - which will (hopefully) help the players understand why they get syntax errors in real programs as well.&lt;/p&gt;

&lt;p&gt;The game also makes you see how the program 'runs', in real life; you follow its progress, and see clearly why it errors (the robot hits a wall, or there is no cupcake to pick). It's also very easy to see if it works correctly or not - you either have a happy robot with a cupcake in hand at the end, or not.&lt;/p&gt;

&lt;h2&gt;How it worked&lt;/h2&gt;

&lt;p&gt;To introduce the game, I held a short &lt;a href="/presentations/RailsGirls%20Krakow/presentation.pdf"&gt;presentation&lt;/a&gt; in which I explained the concept, accompanied by a robot which executed commands, for the attendees to get a glimpse of the available commands and how the robot works. Then we went to playing the game!&lt;/p&gt;

&lt;p&gt;Some teams took a very analytical approach, measuring the step length, calculating how many steps were needed and writing the program in one go. Some were a bit intimidated by the task, and we encouraged them to write some small, test programs, and iterate from there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.facebook.com/photo.php?fbid=384861868294748&amp;amp;set=a.383039768476958.1073741837.350907338356868&amp;amp;type=3&amp;amp;theater"&gt;&lt;img src="/images/RailsGirls/writing%20programs.jpg" alt="Writing programs" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was very exciting for me to see them get involved, the empathy with which they watched their program run, some almost imitating the robot, cheering for it, and celebrating each victory - getting the robot to turn at the right location, getting the second turn right, getting the cupcake.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.facebook.com/photo.php?fbid=384861984961403&amp;amp;set=a.383039768476958.1073741837.350907338356868&amp;amp;type=3&amp;amp;theater"&gt;&lt;img src="/images/RailsGirls/yay%20robots.jpg" alt="Yay, robots!" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The coaches were great robots, executed the programs as rigorously as a machine would do, but error-ed in funny, creative ways.&lt;/p&gt;

&lt;p&gt;After each team wrote a successful program to get the cupcake, we asked them to make it shorter by inventing new commands. They quickly came up with compound commands (step = step right + step left) and repeating instructions (10 x step), turning the ~25 lines of the initial program into less than 10. One team understood that the number of characters must be minimized, so they wrote an algebra-like one-liner like &lt;code&gt;i 10*(x,y) j 7*(x,y) i 4*(x,y) t&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Notes on organizing the game&lt;/h2&gt;

&lt;p&gt;The main challenge was the limited available space, as RailsGirls Krakow had 50 attendees, and about 25 coaches &amp;amp; organizers. To optimize the space, I created 3 labyrinths, each one with 2 robots, and 2 teams x 4 girls per robot. Each labyrinth also had a person that answered questions and interfaced between the teams and the robots. So I made sure that there is enough room for 20 people around each game.&lt;/p&gt;

&lt;p&gt;For the labyrinth itself, the goal was to have it as small as possible, while having at least two paths to go to the cupcake, and at least one long line on each path (to compel them to invent loop commands). We also needed it to be large enough for the robots to walk relatively confortable. After a couple of tests we settled on this shape, and used masking tape directly on the floor to make it:&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/RailsGirls/labyrinth.jpg" alt="labyrinth" /&gt;&lt;/p&gt;

&lt;p&gt;Testing also revealed that it is hard for the (human) robots to make even steps, so we instructed them to make small, tip-to-toe steps. They also called out loud each command as they executed it, and kept track of the current command, to show the error line if the program failed.&lt;/p&gt;

&lt;h2&gt;Thanks&lt;/h2&gt;

&lt;p&gt;Big thanks to &lt;a href="http://webmus.es"&gt;WebMuses&lt;/a&gt; for organizing RailsGirls and having me organize the game. &lt;a href="http://webmus.es/muses"&gt;Monika Starzyk&lt;/a&gt; helped me with ideas, real-life testing, feedback and encouragement. The coaches that volunteered to be robots or to manage labyrinths were awesome. I also thank &lt;a href="http://drtechniko.com/"&gt;DrTechnico&lt;/a&gt;, whose posts about the game inspired me to do it.&lt;/p&gt;

&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="/presentations/RailsGirls%20Krakow/presentation.pdf"&gt;intro presentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/presentations/RailsGirls%20Krakow/cupcakes.pdf"&gt;yummy 3D cupcake&lt;/a&gt; (image from &lt;a href="http://cupcakeipsum.com/"&gt;Cupcake Ipsum&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="/presentations/RailsGirls%20Krakow/program.pdf"&gt;program sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dira.dev/presentations/RailsGirls%20Krakow/robots.pdf"&gt;robot tags&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://drtechniko.com/2012/04/09/how-to-train-your-robot/"&gt;How To Train Your Robot&lt;/a&gt; and &lt;a href="http://drtechniko.com/2012/04/21/teaching-the-how-to-train-your-robot-class/"&gt;Teaching the &amp;#8220;How to train your robot&amp;#8221; class&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
    </entry>
  
</feed>
