<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="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" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-29544026</atom:id><lastBuildDate>Wed, 25 Sep 2024 00:50:35 +0000</lastBuildDate><category>erlang</category><category>flex</category><category>facebook</category><category>mysql</category><category>thrift</category><category>explain</category><category>javascript</category><category>newsletter</category><category>php</category><category>production update</category><category>statistics</category><category>404</category><category>Java</category><category>apache</category><category>asdoc</category><category>cassandra</category><category>cdn</category><category>documentation</category><category>drag and drop</category><category>dynamo</category><category>emacs</category><category>erlounge</category><category>external tools</category><category>fcsh</category><category>flex builder tricks</category><category>garbage collection</category><category>index</category><category>intro</category><category>io_lib_pretty</category><category>jpeg</category><category>jpegoptim</category><category>last.fm</category><category>list comprehensions</category><category>marketing</category><category>msie</category><category>new feature</category><category>new features</category><category>nyc</category><category>opencv</category><category>opensource</category><category>optimization</category><category>optimizer</category><category>performance</category><category>python</category><category>records</category><category>reload</category><category>rex</category><category>scriptaculous</category><category>sort_buffer_size</category><category>ubiquity</category><category>urlencode</category><category>widgets</category><category>xerces</category><category>xml</category><title>Amie Street Dev Blog</title><description></description><link>http://amiest-devblog.blogspot.com/</link><managingEditor>noreply@blogger.com (Lucas)</managingEditor><generator>Blogger</generator><openSearch:totalResults>80</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-6617157565170393602</guid><pubDate>Fri, 27 Feb 2009 00:58:00 +0000</pubDate><atom:updated>2009-02-27T11:01:36.976-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">flex</category><category domain="http://www.blogger.com/atom/ns#">new features</category><category domain="http://www.blogger.com/atom/ns#">widgets</category><title>New Widgets</title><description>We released a few new player widgets today behind the scenes to test a few things out before we integrate them fully into sharing.  Give them a try and let us know where you like them or not.  To get the album or song id, just go to the share page for the song or album and get the last param on the URL.  For example, &lt;a href=&quot;http://amiestreet.com/share/album/DMcjWV2ZhPsx&quot;&gt;http://amiestreet.com/share/album/DMcjWV2ZhPsx&lt;/a&gt; the album id is DMcjWV2ZhPsx.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Treats!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Single Song&lt;/strong&gt;&lt;br /&gt;&lt;object width=&quot;100%&quot; height=&quot;55&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://amiestreet.com/static/swf/AsmwPlayer.swf?songId=J1vZYX0xS2wx&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://amiestreet.com/static/swf/AsmwPlayer.swf?songId=J1vZYX0xS2wx&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;100%&quot; height=&quot;55&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea style=&quot;width: 100%; height: 75px;&quot;&gt;&amp;lt;object height=&quot;55&quot; width=&quot;100%&quot;&amp;gt;&amp;lt;param value=&quot;http://amiestreet.com/static/swf/AsmwPlayer.swf?songId=J1vZYX0xS2wx&quot; name=&quot;movie&quot;/&amp;gt;&amp;lt;param value=&quot;always&quot; name=&quot;allowscriptaccess&quot;/&amp;gt;&amp;lt;embed height=&quot;55&quot; width=&quot;100%&quot; allowfullscreen=&quot;true&quot; allowscriptaccess=&quot;always&quot; type=&quot;application/x-shockwave-flash&quot; src=&quot;http://amiestreet.com/static/swf/AsmwPlayer.swf?songId=J1vZYX0xS2wx&quot;/&amp;gt;&amp;lt;/object&amp;gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Albums&lt;/strong&gt;&lt;br /&gt;&lt;object width=&quot;200&quot; height=&quot;200&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea style=&quot;width: 100%; height: 75px;&quot;&gt;&amp;lt;object width=&quot;200&quot; height=&quot;200&quot;&amp;gt;&amp;lt;param name=&quot;movie&quot; value=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf&quot;&amp;gt;&amp;lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&amp;gt;&amp;lt;embed src=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;200&quot; height=&quot;200&quot;&amp;gt;&amp;lt;/embed&amp;gt;&amp;lt;/object&amp;gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width=&quot;200&quot; height=&quot;200&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf?albumId=DMcjWV2ZhPsx&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf?albumId=DMcjWV2ZhPsx&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;textarea style=&quot;width: 100%; height: 75px;&quot;&gt;&amp;lt;object width=&quot;200&quot; height=&quot;200&quot;&amp;gt;&amp;lt;param name=&quot;movie&quot; value=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf?albumId=DMcjWV2ZhPsx&quot;&amp;gt;&amp;lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&amp;gt;&amp;lt;embed src=&quot;http://amiestreet.com/static/swf/AlbumPlayer.swf?albumId=DMcjWV2ZhPsx&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;200&quot; height=&quot;200&quot;&amp;gt;&amp;lt;/embed&amp;gt;&amp;lt;/object&amp;gt;&lt;/textarea&gt;</description><link>http://amiest-devblog.blogspot.com/2009/02/new-widgets.html</link><author>noreply@blogger.com (Lucas)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-122897553103788058</guid><pubDate>Tue, 03 Feb 2009 01:36:00 +0000</pubDate><atom:updated>2009-02-02T20:52:42.105-05:00</atom:updated><title>Blitzen Trapper Release</title><description>&lt;div style=&quot;float: right; margin-left: 20px;&quot;&gt;&lt;br /&gt;&lt;img src=&quot;http://vox2.cdn.amiestreet.com/album-art/Blitzen-Trapper-by-Blitzen-Trapper_ukfkI1x0GK0x_216w_216h.jpg&quot; /&gt; &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The Blitzen Trapper release is now up and running on production.  This release includes several bug fixes as well as:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://amiestreet.com/music/sigur-ros/med-sud-i-eyrum-vid-spilum-endalaust/&quot;&gt;Improved album pages&lt;/a&gt; - much better handling of compilations and a cleaner layout&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://amiestreet.com/music/ratatat/lp3/mirando&quot;&gt;Song pages&lt;/a&gt; - extended information for individual tracks is now available.  See who&#39;s been listening to this track, RECs for the song, and similar songs.  More importantly, it means when you find a new track your friend doesn&#39;t have to search throuhg the album page to find which one you re actually talking about.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://feeds.feedburner.com/amie-street-new-releases-latest-albums&quot;&gt;Latest Albums RSS&lt;/a&gt; - Much requested and extremely useful &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://beta.amiestreet.com/&quot;&gt;Beta Site&lt;/a&gt; - back up and running.  Will be pushing some new things we&#39;ve been working on out soon&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;</description><link>http://amiest-devblog.blogspot.com/2009/02/blitzen-trapper-release.html</link><author>noreply@blogger.com (Lucas)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-5941475758687179565</guid><pubDate>Wed, 10 Dec 2008 05:50:00 +0000</pubDate><atom:updated>2008-12-10T00:54:31.087-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">erlang</category><category domain="http://www.blogger.com/atom/ns#">erlounge</category><category domain="http://www.blogger.com/atom/ns#">nyc</category><title>Erlounge NYC on Thursday</title><description>The first (afaik?) meeting of Erlounge NYC is this coming Thursday 12/11/08 at 7:30pm at &lt;a href=&quot;http://www.yelp.com/biz/golden-unicorn-new-york&quot;&gt;The Golden Unicorn&lt;/a&gt; in Chinatown, on the 3rd floor.&lt;br /&gt;&lt;br /&gt;If there&#39;s anyone out there interested in learning more about Erlang (or you&#39;re already an Erlang hacker and want to meet others) come join us!</description><link>http://amiest-devblog.blogspot.com/2008/12/erlounge-nyc-on-thursday.html</link><author>noreply@blogger.com (Todd)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-1638367703887690271</guid><pubDate>Mon, 24 Nov 2008 15:00:00 +0000</pubDate><atom:updated>2008-11-24T10:20:06.656-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">last.fm</category><title>Scrobble from Amie Street to Your Last.fm Account</title><description>&lt;div style=&quot;float: left; margin-right: 10px;&quot;&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX1buaB_s5wmWHqWkVDZG2W-wYXZ5gxFd13nRNKtJzPmDKhPIwO0O0MCTqGBlizjjo7MkDzgPYdzO1VceaKrSYCkk9epiXM2IVteQg9Mqu66nH5Tqse5xhIcQ7yMWu9T5D77ov/s1600-h/lastfm_logo.jpg&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 100px; height: 102px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX1buaB_s5wmWHqWkVDZG2W-wYXZ5gxFd13nRNKtJzPmDKhPIwO0O0MCTqGBlizjjo7MkDzgPYdzO1VceaKrSYCkk9epiXM2IVteQg9Mqu66nH5Tqse5xhIcQ7yMWu9T5D77ov/s320/lastfm_logo.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5272241993439302962&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;In the latest production update, we finally pushed out the code to scrobble anything you listen to on Amie Street, whether its from the bottom player, popout player, library player, or any widgets, to your last.fm account.  Along with the standard scrobbling, your now playing status will also be updated every time you start a playing a song on Amie Street.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;To enable scrobbling, click on the &lt;a href=&quot;http://amiestreet.com/profile/account&quot;&gt;&quot;Account&quot; tab&lt;/a&gt; on Amie Street and at the bottom under &quot;Other Services&quot;, click on the &lt;a href=&quot;http://amiestreet.com/profile/account/lastfm&quot;&gt;&quot;Last.fm Settings&quot;&lt;/a&gt; link.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;You can also join us in the &lt;a href=&quot;http://www.last.fm/group/AmieStreet.com&quot;&gt;AmieStreet.com group&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;</description><link>http://amiest-devblog.blogspot.com/2008/11/scrobble-from-amie-street-to-your.html</link><author>noreply@blogger.com (Lucas)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX1buaB_s5wmWHqWkVDZG2W-wYXZ5gxFd13nRNKtJzPmDKhPIwO0O0MCTqGBlizjjo7MkDzgPYdzO1VceaKrSYCkk9epiXM2IVteQg9Mqu66nH5Tqse5xhIcQ7yMWu9T5D77ov/s72-c/lastfm_logo.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-8646556719542531726</guid><pubDate>Tue, 21 Oct 2008 03:51:00 +0000</pubDate><atom:updated>2008-11-01T13:57:14.833-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>Delayed selectors in jQuery</title><description>On our new &lt;a href=&quot;http://beta.amiestreet.com/&quot;&gt;redesign&lt;/a&gt; we&#39;re doing a lot of crazy JavaScript and have come up with some interesting solutions to interesting problems. Today I was working on a problem where hitting the &quot;play&quot; button for a song before the player SWF had loaded caused a JS error on the page. It was trying to call a JS method on the swf, but the method didn&#39;t exist yet.&lt;br /&gt;&lt;br /&gt;I came up with this interesting solution which is extensible and reusable for a lot of use cases. Here&#39;s a concise illustration of the technique:&lt;br /&gt;&lt;br /&gt;&lt;pre style=&#39;color:#000000;background:#ffffff;&#39;&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;html&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;head&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;title&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;Test&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;title&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;head&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;body&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;script src=&quot;http://www.google.com/jsapi&quot;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;script&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;script&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;google&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;load&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&quot;jquery&quot;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt; &lt;span style=&#39;color:#0000e6; &#39;&gt;&quot;1&quot;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;google&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;setOnLoadCallback&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  DelayProxy &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;sel&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;this&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;sel &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; sel&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;var&lt;/span&gt; self &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;this&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;this&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;interval &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; setInterval&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt; self&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;try&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt; &lt;span style=&#39;color:#008c00; &#39;&gt;100&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  DelayProxy&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;prototype &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;    queue&lt;span style=&#39;color:#800080; &#39;&gt;:&lt;/span&gt; &lt;span style=&#39;color:#808030; &#39;&gt;[&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;]&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;__noSuchMethod__&#39;&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;:&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;id&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt; args&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;this&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;queue&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;push&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;[&lt;/span&gt;id&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt; args&lt;span style=&#39;color:#808030; &#39;&gt;]&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;try&#39;&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;:&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;var&lt;/span&gt; res &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; $&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;this&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;sel&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;if&lt;/span&gt; &lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;res&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;length&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;        clearTimeout&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;this&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;interval&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;for&lt;/span&gt; each &lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;var&lt;/span&gt; call &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;in&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;this&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;queue&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;          res&lt;span style=&#39;color:#808030; &#39;&gt;[&lt;/span&gt;call&lt;span style=&#39;color:#808030; &#39;&gt;[&lt;/span&gt;&lt;span style=&#39;color:#008c00; &#39;&gt;0&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;]&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;]&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;apply&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;res&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt; call&lt;span style=&#39;color:#808030; &#39;&gt;[&lt;/span&gt;&lt;span style=&#39;color:#008c00; &#39;&gt;1&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;]&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  $&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;whenAvailable &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;target&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;var&lt;/span&gt; els &lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt; $&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;target&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;if&lt;/span&gt; &lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;els&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;length&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;return&lt;/span&gt; els&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;else&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;return&lt;/span&gt; &lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;new&lt;/span&gt; DelayProxy&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;target&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  $&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;#run-test&#39;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;click&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;    $&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;whenAvailable&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;#target&#39;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;attr&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;value&#39;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;,&lt;/span&gt; &lt;span style=&#39;color:#0000e6; &#39;&gt;&quot;hello world!&quot;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  $&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;#make-target&#39;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;click&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;function&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt; &lt;span style=&#39;color:#800080; &#39;&gt;{&lt;/span&gt;&lt;br /&gt;    $&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;body&#39;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;.&lt;/span&gt;append&lt;span style=&#39;color:#808030; &#39;&gt;(&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&#39;&amp;lt;input type=&quot;text&quot; id=&quot;target&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&#39;color:#800080; &#39;&gt;}&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;)&lt;/span&gt;&lt;span style=&#39;color:#800080; &#39;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;script&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;a&lt;/span&gt;&lt;span style=&#39;color:#274796; &#39;&gt; &lt;/span&gt;&lt;span style=&#39;color:#074726; &#39;&gt;href&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&quot;#&quot;&lt;/span&gt;&lt;span style=&#39;color:#274796; &#39;&gt; &lt;/span&gt;&lt;span style=&#39;color:#074726; &#39;&gt;id&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&quot;run-test&quot;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;Set target value&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;a&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;a&lt;/span&gt;&lt;span style=&#39;color:#274796; &#39;&gt; &lt;/span&gt;&lt;span style=&#39;color:#074726; &#39;&gt;href&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&quot;#&quot;&lt;/span&gt;&lt;span style=&#39;color:#274796; &#39;&gt; &lt;/span&gt;&lt;span style=&#39;color:#074726; &#39;&gt;id&lt;/span&gt;&lt;span style=&#39;color:#808030; &#39;&gt;=&lt;/span&gt;&lt;span style=&#39;color:#0000e6; &#39;&gt;&quot;make-target&quot;&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;Make target&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;a&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;body&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#39;color:#800000; font-weight:bold; &#39;&gt;html&lt;/span&gt;&lt;span style=&#39;color:#a65700; &#39;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can try this demo &lt;a href=&quot;http://src.amiestreet.com/delayed.html&quot;&gt;here&lt;/a&gt;. First click &quot;make target&quot; and then &quot;set target value&quot;. Nothing special going on - we&#39;re inserting a text field into the DOM, then setting its value using the jQuery &lt;code&gt;attr&lt;/code&gt; function. Now reload the page so the inserted field goes away and hit the links in the opposite order. As soon as you hit &quot;make target&quot; the delayed &quot;set target value&quot; call should execute.&lt;br /&gt;&lt;br /&gt;The real trick behind this code is the &lt;code&gt;__noSuchMethod__&lt;/code&gt; function. If an object has this property set to a function, it will be called for any missing member function call, and will receive the function name and arguments as arguments. It&#39;s similar to PHP&#39;s &lt;code&gt;__call&lt;/code&gt; or perl&#39;s &lt;code&gt;AUTOLOAD&lt;/code&gt; and comes in really handy. Here&#39;s how the code works:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;When you call &lt;code&gt;$.whenAvailable&lt;/code&gt;, it checks with jQuery to see if the selector has any matching elements. Since it doesn&#39;t, it returns a new &lt;code&gt;DelayProxy&lt;/code&gt; object. The constructor of the &lt;code&gt;DelayProxy&lt;/code&gt; sets up a timer which calls &lt;code&gt;try&lt;/code&gt; every 100ms.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;When you call &lt;code&gt;attr(...)&lt;/code&gt; on the DelayProxy, it fires the &lt;code&gt;__noSuchMethod__&lt;/code&gt; function. This pushes onto the internal queue.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;When you later hit the &quot;Make target&quot; button, the selector becomes valid&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Some amount of time (&lt;100ms) later, the timer fires and &lt;code&gt;DelayProxy.try&lt;/code&gt; finds the selector. This kills itself (&lt;code&gt;clearTimeout&lt;/code&gt;) and then applies the queued up function(s) to the resulting selector.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Pretty neat! I used to hate JS, but it does have some pretty powerful tricks.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;update:&lt;/strong&gt; it turns out this is a Mozilla SpiderMonkey extension, and hence not really useful in the real world. Boo!! The same idea still applies, but you&#39;ve got to manually register the function for each of the functions to be delayed.</description><link>http://amiest-devblog.blogspot.com/2008/10/delayed-selectors-in-jquery.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-6269272764554176666</guid><pubDate>Thu, 25 Sep 2008 15:02:00 +0000</pubDate><atom:updated>2008-09-25T12:37:11.366-04:00</atom:updated><title>Flex Tree Component Bug</title><description>Yesterday I encountered a bug with setting the selectedIndex of the Flex tree component. The default behavior for dropping an item onto a Tree, or any List control, is to drop items in between the items currently in the list. I, however, wanted to drop items onto the items currently in the list. One common way to do this is to set a handler for the dragOver event of the Tree and in this handler call calculateDropIndex on the Tree and set the Tree&#39;s selectedIndex equal to this result. This gives some nice visual feedback and lets you easily get access to the element in the Tree at the target drop location.&lt;br /&gt;&lt;br /&gt;The problem I encountered manifests itself when a new item is added to the Tree. In particular, if the dataProvider of the Tree is an Array, there seems to be an off-by-one error when dragging over the elements of the Tree after an element has been added to the underlying Array. If you use an ArrayCollection as the dataProvider for the Tree, everything works fine.&lt;br /&gt;&lt;br /&gt;In the demo below, try dragging any of the elements in the two Trees over the other elements in the Tree. All seems to work. Now reset the demo, and click the &quot;Add Item&quot; button for the Tree on the right (the one backed by the ArrayCollection.) Note that it continues to work as expected. Now try to do the same thing with the Tree on the left. After doing a fresh reset and clicking &quot;Add Item&quot;, good luck trying to drop something onto the element with label &quot;5&quot;.&lt;br /&gt;&lt;br /&gt;After doing a small amount of debugging, I&#39;ve come to the conclusion that the calculateDropIndex method is always returning the right value, but that setting selectedIndex is not correctly finding the right element in the Tree.&lt;br /&gt;&lt;br /&gt;You can check out the source for this &lt;a href=&quot;http://src.amiestreet.com/TreeBug.mxml&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;object height=&quot;250&quot; width=&quot;225&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://src.amiestreet.com/TreeBug.swf&quot;&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://src.amiestreet.com/TreeBug.swf&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; height=&quot;250&quot; width=&quot;225&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://amiest-devblog.blogspot.com/2008/09/flex-tree-component-bug.html</link><author>noreply@blogger.com (Aaron)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-651731865877923703</guid><pubDate>Thu, 18 Sep 2008 17:23:00 +0000</pubDate><atom:updated>2008-09-18T13:24:51.646-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">404</category><category domain="http://www.blogger.com/atom/ns#">apache</category><category domain="http://www.blogger.com/atom/ns#">urlencode</category><title>How to fix: slashes urlencoded as %2F giving 404 in Apache</title><description>I ran into a problem today where URLs that contained &quot;%2F&quot; in them were giving 404s in Apache. By enabling mod_rewrite logging it became evident that Apache was short circuiting the request even before entering the module.&lt;br /&gt;&lt;br /&gt;After some googling I came upon the &lt;a href=&quot;http://httpd.apache.org/docs/2.2/mod/core.html#allowencodedslashes&quot;&gt;AllowEncodedSlashes&lt;/a&gt; directive. I have no idea why this is off by default, but it fixes the problem.</description><link>http://amiest-devblog.blogspot.com/2008/09/how-to-fix-slashes-urlencoded-as-2f.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-826866675620134268</guid><pubDate>Mon, 15 Sep 2008 19:59:00 +0000</pubDate><atom:updated>2008-09-15T16:19:36.099-04:00</atom:updated><title>Pet Peeve of the Week: Commented Code</title><description>My fellow engineers at Amie Street can attest that I am full of almost inexplicable hatred for some very specific things. Today I would like to rant about my hatred for commented code.&lt;br /&gt;&lt;br /&gt;By commented code, I don&#39;t mean the good kind of commented code. You know, the kind where it answers the questions you have about how something works but doesn&#39;t ramble on. I love this kind of commented code and try to write it wherever possible. Good commented code looks something like:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Parse a color parameter in the request. Expected format is&lt;br /&gt;     * six digit hex (like in HTML but without the #)&lt;br /&gt;     */&lt;br /&gt;    private function getColorParam($request, $param, $default=&#39;FFFFFF&#39;) {&lt;br /&gt;...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;or maybe:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;        // Copy topleft corner&lt;br /&gt;        imagecopy(&lt;br /&gt;            $targetIm, $templateIm,&lt;br /&gt;            0, 0,&lt;br /&gt;            0, 0,&lt;br /&gt;            $slice_l, $slice_t);&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Today I&#39;m ranting about the bad kind of commented code. You know, the kind of commented code that is actually code that has been commented out. It looks like this:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;public function newReleasesAction($request) {&lt;br /&gt;    /*&lt;br /&gt;    $n = date(&#39;N&#39;, time());&lt;br /&gt;    if($n==2){&lt;br /&gt;           // Its tuesday&lt;br /&gt;        $dateString = date(&quot;F jS&quot;, time());&lt;br /&gt;    }&lt;br /&gt;    else{&lt;br /&gt;           $dateString = date(&quot;F jS&quot;, strtotime(&#39;last Tuesday&#39;));&lt;br /&gt;    }&lt;br /&gt;    */&lt;br /&gt;    $dateString = date(&quot;F jS&quot;, Amie_DB::getUnixTimeForNow());&lt;br /&gt;    $this-&gt;stash(&#39;newReleasesDate&#39;, $dateString);&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Note that the majority of the above code has been commented out with a block comment. Rather than answering questions, this kind of insidious &quot;comment&quot; leaves you with more. Mainly, &lt;b&gt;why is it commented out?&lt;/b&gt; The developer trying to read this code can make several different guesses:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;The code isn&#39;t necessary anymore&lt;/b&gt; - Maybe this code used to be important, but the variable it&#39;s setting wasn&#39;t used anywhere so someone commented out.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;The code didn&#39;t work properly&lt;/b&gt; - the commented code was causing problems, so someone replaced it with the line below the comment block. The replacement code may or may not do the same thing as the original, but the developer needed to patch the issue to get the page to load, or whatever.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;The code was commented out for debugging purposes and someone forgot to uncomment it&lt;/b&gt;. This kind of thing happens all the time - how often have you made a commit with random error logs like &quot;Got here&quot; in your codebase?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;The code was replaced with a better version (or refactored) but someone had an emotional attachment&lt;/b&gt;- for some reason some developers are afraid of the delete key and the rm command.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Frankly, every one of these reasons is stupid. One by one:&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The code isn&#39;t necessary anymore&lt;/h2&gt;&lt;br /&gt;Delete it! If you ever find that it becomes necessary again, this is why you use version control.&lt;br /&gt;&lt;h2&gt;The code didn&#39;t work properly&lt;/h2&gt;&lt;br /&gt;Commenting it out just risks that someone else will come and uncomment it again at a later date. If you don&#39;t know how to fix it, you should replace the broken code with something like &quot;/* TODO: the algorithm that used to be here had a flaw. See bug #234291. Replaced algorithm with hardcoded data below */&quot; or something of that nature.&lt;br /&gt;&lt;h2&gt;The code was commented out for debugging&lt;/h2&gt;&lt;br /&gt;Can&#39;t say I haven&#39;t done this plenty of times myself, but before you commit it&#39;s good practice to do a quick diff to make sure you haven&#39;t inadvertently added useless log messages or commented out code that should be working.&lt;br /&gt;&lt;h2&gt;The emotional attachment&lt;/h2&gt;&lt;br /&gt;Get over it! If you ever want to admire your old work you can always check out an old version of the code from the repository. It&#39;s pretty easy to pull back old code, but being a code packrat is kind of like taking your leftovers at dinner, putting them in a shoebox, and shoving them under your bed in case you&#39;re hungry in a couple of weeks. When you come back to the dead code it will be full of bugs that have grown since it was last used.</description><link>http://amiest-devblog.blogspot.com/2008/09/pet-peeve-of-week-commented-code.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-8035949803010183752</guid><pubDate>Fri, 12 Sep 2008 16:51:00 +0000</pubDate><atom:updated>2008-09-12T13:57:16.105-04:00</atom:updated><title>Getting Click Events from the Slider Track in Flex</title><description>In the past few days I&#39;ve run into two separate situations in which I needed to be able to get an event when the track of a slider was clicked. In one case, I was using an HSlider control to set the volume of a music player. When the track was clicked the thumb of the slider would nicely tween to its new position, but the volume of the sound would abruptly jump when the thumb was done moving.&lt;br /&gt;&lt;br /&gt;Ideally you would be able to tween the volume at the same rate that the slider thumb is moving, but to do this you need to be able to know when the track is clicked, before the slider thumb is done moving. Furthermore, you need to know the values the slider is moving from and to.&lt;br /&gt;&lt;br /&gt;Ordinarily, the only event the slider component will dispatch when the track is clicked is the &quot;change&quot; event, and this happens after the slider thumb is done moving to the new location on the track. It is possible, however, to receive the track click event by extending the HSlider or VSlider classes. Below is some example code. Though we shouldn&#39;t really be accessing mx_internal members, I can&#39;t see any other way to do it. I&#39;m open to suggestions as to another way to get access to this event, and the from and to values of the slider.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;pre&gt;&lt;br /&gt;package {&lt;br /&gt; import flash.events.MouseEvent;&lt;br /&gt; import mx.controls.HSlider;&lt;br /&gt; import mx.core.mx_internal;&lt;br /&gt;&lt;br /&gt; use namespace mx_internal;&lt;br /&gt;&lt;br /&gt; public class ExtendedHSlider extends HSlider {&lt;br /&gt;   override protected function createChildren():void {&lt;br /&gt;     super.createChildren();&lt;br /&gt;&lt;br /&gt;     super.mx_internal::getTrackHitArea().addEventListener(MouseEvent.MOUSE_DOWN,&lt;br /&gt;       function(event:MouseEvent):void {&lt;br /&gt;         var fromValue:Number = value;&lt;br /&gt;         var toValue:Number = mx_internal::getValueFromX(event.localX);&lt;br /&gt;         trace(&quot;Hooray! We&#39;re getting events when the track is clicked!&quot;);&lt;br /&gt;         trace(&quot;The slider is going to move from &quot; + fromValue + &quot; to &quot; + toValue);&lt;br /&gt;       });&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;</description><link>http://amiest-devblog.blogspot.com/2008/09/getting-click-events-from-slider-track.html</link><author>noreply@blogger.com (Aaron)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-7333212829305107666</guid><pubDate>Thu, 11 Sep 2008 06:57:00 +0000</pubDate><atom:updated>2008-09-11T03:01:43.947-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">mysql</category><category domain="http://www.blogger.com/atom/ns#">sort_buffer_size</category><title>big sort_buffer_size causes slow filesort</title><description>I spent several hours tonight trying to track down why a 12-row filesort was taking upwards of 30ms on our production DBs. After installing 4 different versions of mysql and not figuring anything out, I finally took a guess and &lt;em&gt;decreased&lt;/em&gt; &lt;code&gt;sort_buffer_size&lt;/code&gt; from 64M to 256K.&lt;br /&gt;&lt;br /&gt;I&#39;m not entirely sure why I thought a 64M sort buffer was a great idea, but it turns out it&#39;s a terrible one! After setting it to 256K the query returns in 0.00sec as expected.&lt;br /&gt;&lt;br /&gt;Looks like the guys at Percona &lt;a href=&quot;http://www.mysqlperformanceblog.com/2007/08/18/how-fast-can-you-sort-data-with-mysql/&quot;&gt;have noticed this too&lt;/a&gt;.</description><link>http://amiest-devblog.blogspot.com/2008/09/big-sortbuffersize-causes-slow-filesort.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-7589958321933846483</guid><pubDate>Tue, 09 Sep 2008 01:58:00 +0000</pubDate><atom:updated>2008-09-08T22:30:49.510-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">performance</category><category domain="http://www.blogger.com/atom/ns#">php</category><title>array_intersect_key is terrible</title><description>I always had a hunch that array_intersect_key was slow in PHP, but I didn&#39;t quite realize &lt;em&gt;how&lt;/em&gt; slow until tonight when I decided to benchmark it. Here&#39;s a quick test script:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&lt;?php&lt;br /&gt;&lt;br /&gt;$big = array();&lt;br /&gt;for ($i = 0; $i &lt; 10000; $i++) {&lt;br /&gt;    $big[$i] = 234;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$small = array();&lt;br /&gt;for ($i = 0; $i &lt; 10; $i++) {&lt;br /&gt;    $big[$i] = 2435;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;////////////////////////////////////////////////////////////&lt;br /&gt;&lt;br /&gt;print &quot;Testing big first\n&quot;;&lt;br /&gt;&lt;br /&gt;$st = microtime(true);&lt;br /&gt;for ($i = 0; $i &lt; 100; $i++) {&lt;br /&gt;    $junk = array_intersect_key($big, $small);&lt;br /&gt;}&lt;br /&gt;$bigfirst = microtime(true) - $st;&lt;br /&gt;&lt;br /&gt;////////////////////////////////////////////////////////////&lt;br /&gt;&lt;br /&gt;print &quot;Testing small first\n&quot;;&lt;br /&gt;&lt;br /&gt;$st = microtime(true);&lt;br /&gt;for ($i = 0; $i &lt; 100; $i++) {&lt;br /&gt;    $junk = array_intersect_key($small, $big);&lt;br /&gt;}&lt;br /&gt;$smallfirst = microtime(true) - $st;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;print &quot;array_intersect_key\n&quot;;&lt;br /&gt;print &quot;========================================\n&quot;;&lt;br /&gt;print &quot;Big first:   $bigfirst\n&quot;;&lt;br /&gt;print &quot;Small first: $smallfirst\n&quot;;&lt;br /&gt;&lt;br /&gt;////////////////////////////////////////////////////////////&lt;br /&gt;&lt;br /&gt;function common_keys($a, $b) {&lt;br /&gt;    $res = array();&lt;br /&gt;    foreach ($a as $key =&gt; $val) {&lt;br /&gt;        if (isset($b[$key]))&lt;br /&gt;            $res[] = $key;&lt;br /&gt;    }&lt;br /&gt;    return $res;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;print &quot;Testing big first\n&quot;;&lt;br /&gt;&lt;br /&gt;$st = microtime(true);&lt;br /&gt;for ($i = 0; $i &lt; 100; $i++) {&lt;br /&gt;    $junk = common_keys($big, $small);&lt;br /&gt;}&lt;br /&gt;$bigfirst = microtime(true) - $st;&lt;br /&gt;&lt;br /&gt;////////////////////////////////////////////////////////////&lt;br /&gt;&lt;br /&gt;print &quot;Testing small first\n&quot;;&lt;br /&gt;&lt;br /&gt;$st = microtime(true);&lt;br /&gt;for ($i = 0; $i &lt; 100; $i++) {&lt;br /&gt;    $junk = common_keys($small, $big);&lt;br /&gt;}&lt;br /&gt;$smallfirst = microtime(true) - $st;&lt;br /&gt;&lt;br /&gt;////////////////////////////////////////////////////////////&lt;br /&gt;&lt;br /&gt;print &quot;common_keys\n&quot;;&lt;br /&gt;print &quot;========================================\n&quot;;&lt;br /&gt;print &quot;Big first:   $bigfirst\n&quot;;&lt;br /&gt;print &quot;Small first: $smallfirst\n&quot;;&lt;br /&gt;?&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And the results:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Testing big first&lt;br /&gt;Testing small first&lt;br /&gt;array_intersect_key&lt;br /&gt;========================================&lt;br /&gt;Big first:   13.1110720634&lt;br /&gt;Small first: 12.5442099571&lt;br /&gt;Testing big first&lt;br /&gt;Testing small first&lt;br /&gt;common_keys&lt;br /&gt;========================================&lt;br /&gt;Big first:   0.363513946533&lt;br /&gt;Small first: 0.000243902206421&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;By implementing this in pure PHP you get a 50000x speedup over using the built-in in some cases. Wow...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; this appears to be fixed in PHP 5.2.5. See the &lt;a href=&quot;http://www.php.net/releases/5_2_5.php&quot;&gt;Release Notes&lt;/a&gt;.</description><link>http://amiest-devblog.blogspot.com/2008/09/arrayintersectkey-is-terrible.html</link><author>noreply@blogger.com (Todd)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-6579618482296038962</guid><pubDate>Thu, 04 Sep 2008 14:13:00 +0000</pubDate><atom:updated>2008-09-04T11:21:21.097-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">flex</category><category domain="http://www.blogger.com/atom/ns#">ubiquity</category><title>Flexdoc for Ubiquity</title><description>Mike Chambers &lt;a href=&quot;http://www.mikechambers.com/blog/2008/09/03/actionscript-3-api-service-on-google-app-engine/&quot;&gt;whipped up an API for AS3 reference&lt;/a&gt; on Google App Engine yesterday.  The API allows you to send a class name or fragment of a class name a get the links to the livedocs pages for any matches. Combine this with &lt;a href=&quot;https://wiki.mozilla.org/Labs/Ubiquity&quot;&gt;Ubiquity&lt;/a&gt; and you have a super simple way to get to livedocs for any AS3 class.  To install Ubiquity, you can grab the &lt;a href=&quot;https://people.mozilla.com/%7Eavarma/ubiquity-0.1.xpi&quot;&gt;xpi from here&lt;/a&gt;. To add the command, go to &lt;a href=&quot;http://hrabovsky.lucas.googlepages.com/ubiquity_flexdoc&quot;&gt;this page&lt;/a&gt; and just click the subscribe button in the top right. &lt;br /&gt;&lt;p&gt;&lt;a href=&quot;http://gist.github.com/8780&quot;&gt;ubiquity_flexdoc gist&lt;/a&gt;&lt;/p&gt;</description><link>http://amiest-devblog.blogspot.com/2008/09/flexdoc-for-ubiquity.html</link><author>noreply@blogger.com (Lucas)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-7104549051201329220</guid><pubDate>Sat, 30 Aug 2008 06:02:00 +0000</pubDate><atom:updated>2008-08-30T02:37:45.577-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">drag and drop</category><category domain="http://www.blogger.com/atom/ns#">flex</category><title>Custom Drag and Drop for Lists in Flex 3</title><description>Yesterday I spent far too long trying to figure out why my custom dragDrop handler for the Flex 3 mx.controls.Tree class wasn&#39;t being called.&lt;br /&gt;&lt;br /&gt;I had all the relevant callbacks (dragDrop, dragEnter, dragOver, dragExit) registered, had trace() statements in place so I could watch their behavior, and had dropEnabled set to true on the Tree. I could see trace() output coming from my dragEnter, dragOver and dragExit handlers. Still, I was getting nothing from the only one which really mattered: dragDrop. I tried playing around with DragManager.acceptDragDrop, tried calling preventDefault() as the first call in the event callbacks, and various other voodoo, but all to no avail. What could possibly be wrong?&lt;br /&gt;&lt;br /&gt;The answer: in order for the dragDrop callback you set to actually get called, you need to set dropEnabled to false! The property described by Adobe as &quot;A flag that indicates whether dragged items can be dropped onto the        control&quot; has to be set to &quot;false&quot; in order to actually receive the dragDrop event. Go figure.&lt;br /&gt;&lt;br /&gt;The semantics of this property are, in reality, &quot;A flag that indicates whether to use the default behavior for accepting dragged items, which is to assume that the object being dropped here is the object we expect, and to accept all. Set to false if you want to override this behavior.&quot;&lt;br /&gt;&lt;br /&gt;This isn&#39;t just true for the Tree class, either. This is true for all controls which inherit from ListBase, which is quite a few, including HorizontalList, TileList, FileSystemList, Menu, Tree and DataGrid. Hopefully in Flex 4 sanity will prevail and they&#39;ll rename this property something a little more intuitive.&lt;br /&gt;&lt;br /&gt;Side note: I also considered the title &quot;Worst Property Name Ever&quot; for this post.</description><link>http://amiest-devblog.blogspot.com/2008/08/custom-drag-and-drop-in-flex-3-for.html</link><author>noreply@blogger.com (Aaron)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-1793241549421552281</guid><pubDate>Tue, 12 Aug 2008 03:33:00 +0000</pubDate><atom:updated>2008-08-11T23:34:12.972-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">opencv</category><category domain="http://www.blogger.com/atom/ns#">python</category><title>How to crop images with opencv in python</title><description>I just spent way too long figuring this out, so I figured I&#39;d contribute to the google knowledge:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;    cropped = cvCreateImage( cvSize(new_width, new_height), 8, 3)&lt;br /&gt;    src_region = cvGetSubRect(image, opencv.cvRect(left, top, new_width, new_height) )&lt;br /&gt;    cvCopy(src_region, cropped)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You&#39;d think this would be easy and/or documented, but nope!</description><link>http://amiest-devblog.blogspot.com/2008/08/how-to-crop-images-with-opencv-in.html</link><author>noreply@blogger.com (Todd)</author><thr:total>6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-1214744979000464053</guid><pubDate>Thu, 07 Aug 2008 13:09:00 +0000</pubDate><atom:updated>2008-08-07T09:57:56.231-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">marketing</category><category domain="http://www.blogger.com/atom/ns#">statistics</category><title>Advice for Startup Marketing Advice - Learn Statistics</title><description>An interesting blog post, entitled &lt;a href=&quot;http://laserlike.com/2008/07/16/startup-marketing-advice/&quot;&gt;Startup Marketing Advice&lt;/a&gt; came across &lt;a href=&quot;http://delicious.com/tlipcon&quot;&gt;my delicious&lt;/a&gt; network this past week. In this post, the author espouses the merits of the scientific method to determine catchy and effective marketing messaging in a cheap and effective way.&lt;br /&gt;&lt;br /&gt;I have no problem with the thesis of the post. He&#39;s completely right that A/B testing is a terrific way to determine whether one message is better than another. Every elementary schooler knows that a good experiment has a control group and a test group, and the way to show that the variable under test is significant is to demonstrate that the test group responds significantly differently from the control.&lt;br /&gt;&lt;br /&gt;The problem, though, is that the example given in the post doesn&#39;t prove anything! We&#39;ll look at the top two messages in his adwords result list (&quot;Startup Marketing Advice&quot; and &quot;Marketing with Adwords&quot;) and show that there is no significant clickthrough rate difference.&lt;br /&gt;&lt;br /&gt;The first problem that should stand out is that the number of clicks is so small that the proportions cannot be accurately estimated. The general rule of thumb for estimating a proportion is that you need at least 5 positive and 5 negative examples. The trial with the most clicks in his experiment only received 4 clicks. Therefore the CTR%s given by Google hardly mean anything - the standard error (calculated sqrt(p(1-p)/n) for a binomial proportion like CTR) can&#39;t be accurately determined, but is sure to be nearly as large as the CTR itself.&lt;br /&gt;&lt;br /&gt;The second problem is the assessment of statistical significance between the different choices. The standard error of the difference between two estimators is sqrt(S_1^2/n_1 + S_2^2/n_2). Calculating this for the top two adwords campaigns, we see that the standard error for the difference between their clickthrough rates is somewhere in the vicinity of 0.35%. [Again, the statistics here are all inaccurate because we&#39;ve already failed the &quot;minimum of 5 clicks&quot; rule of thumb, but we&#39;ll ignore that.] Because the measured CTR difference is 0.55-0.30 = 0.25, we calculate a Z score of (0.25 / 0.35) = 0.71. Looking this up in a table of the normal distribution we can find out that this is equivalent to about 75% significance that campaign 1 is better than campaign 2. This doesn&#39;t sound too terrible, but it&#39;s hardly scientific, especially when you consider the small sample sizes as mentioned earlier.&lt;br /&gt;&lt;br /&gt;&lt;smaller&gt;&lt;b&gt;Note&lt;/b&gt;: I am not a statistician. I just play one on a blog.&lt;/smaller&gt;</description><link>http://amiest-devblog.blogspot.com/2008/08/advice-for-startup-marketing-advice.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-1986347299740784857</guid><pubDate>Thu, 03 Jul 2008 05:52:00 +0000</pubDate><atom:updated>2008-07-03T02:00:32.876-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">cassandra</category><category domain="http://www.blogger.com/atom/ns#">dynamo</category><category domain="http://www.blogger.com/atom/ns#">facebook</category><title>Cassandra source on Google Code</title><description>As predicted, Facebook has open sourced Cassandra. It&#39;s &lt;a href=&quot;http://code.google.com/p/the-cassandra-project/&quot;&gt;available on Google Code&lt;/a&gt; with very little fanfare.&lt;br /&gt;&lt;br /&gt;Some notes after my browsing through the source:&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;It uses hinted handoff and bootstrapping just like Amazon&#39;s Dynamo&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Its consistency model doesn&#39;t seem to be quite the same - Dynamo uses vector clocks to determine causal relationships, whereas Cassandra seems to be just based on timestamps and &quot;majority rules&quot; semantics when timestamps are tied.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Membership is communicated by a gossip protocol as described in the Dynamo paper.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Requests are made to the system by sending thrift calls to any node. The thrift interface is included in the source.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Some further thoughts:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;It doesn&#39;t seem like there&#39;s a lock on the table during bootstrapping. What happens to mutations made on the source node while it is bootstrapping the destination? Are they marked for later hinted handoff?&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Would system performance be improved by using the new Thrift TNonblockingServer (see THRIFT-5 on JIRA)? It should be more scalable than the TThreadPoolServer they&#39;re using now.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Cassandra is around 40K lines of Java. How many lines would an equivalent Erlang program be, and what would be the performance difference?&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;All in all, it&#39;s a very interesting project sure to attract much attention. Now that Powerset has been acquired by Microsoft, I&#39;m a little worried for Hbase&#39;s future -- two of the three main developers are Powerset employees. Maybe Cassandra can help fill the open source scalable database niche.</description><link>http://amiest-devblog.blogspot.com/2008/07/cassandra-source-on-google-code.html</link><author>noreply@blogger.com (Todd)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-7495240854462814840</guid><pubDate>Mon, 30 Jun 2008 14:59:00 +0000</pubDate><atom:updated>2008-06-30T11:08:27.267-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">facebook</category><category domain="http://www.blogger.com/atom/ns#">opensource</category><title>Facebook&#39;s next open source projects: Hive and Cassandra</title><description>A couple weeks ago, Jeff Hammerbacher from Facebook presented some details on &lt;a href=&quot;http://www.slideshare.net/jhammerb/20080611accel?src=embed&quot;&gt;Cassandra&lt;/a&gt; (see later slides), a structured p2p storage system similar to Google&#39;s &lt;a href=&quot;http://labs.google.com/papers/bigtable.html&quot;&gt;Bigtable&lt;/a&gt; or Amazon&#39;s &lt;a href=&quot;http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html&quot;&gt;Dynamo&lt;/a&gt;. What is most interesting about Cassandra is that they seem to be preparing to open source it imminently. Jeff bookmarked two things on delicious last night:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://cassandra.wikidot.com/&quot;&gt;Cassandra: Welcome to your new Wikidot site&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;&lt;a href=&quot;https://launchpad.net/cassandra&quot;&gt;Cassandra: A Structured Storage System on a P2P Network in Launchpad&lt;/a&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Both sites are empty as of now, but it looks like they&#39;re planning on releasing the source some time soon using bzr for version control.&lt;br /&gt;&lt;br /&gt;Another interesting Facebook project is Hive, a sort of data warehousing solution built on Hadoop. They&#39;ve been discussing open sourcing this for several months now, but it looks like things are starting to happen with &lt;a href=&quot;https://issues.apache.org/jira/browse/HADOOP-3601&quot;&gt;HADOOP-3601: Hive as contrib project&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;On the non-Facebook open source front, we&#39;ve got some news coming soon as well. We&#39;ve made the decision to open source several of our internal tools under an MIT license - hold tight for more info.</description><link>http://amiest-devblog.blogspot.com/2008/06/facebooks-next-open-source-projects.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-2984707059588565113</guid><pubDate>Mon, 23 Jun 2008 17:30:00 +0000</pubDate><atom:updated>2008-06-23T13:37:32.366-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">msie</category><category domain="http://www.blogger.com/atom/ns#">scriptaculous</category><title>How to work around an MSIE bug with Scriptaculous</title><description>For several months we&#39;ve noticed a lot of 404s in our access logs that look like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;x.x.x.x - - [2008-06-23 13:14:30] &quot;GET /static/r/toLRhQ/js/&#39;+libraryName+&#39; HTTP/1.1&quot; 404 549 - &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;1813)&quot;&lt;br /&gt;x.x.x.x - - [2008-06-23 13:14:30] &quot;GET /static/r/toLRhQ/js/&#39;+libraryName+&#39; HTTP/1.1&quot; 404 568 - &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;1813)&quot;&lt;br /&gt;x.x.x.x - - [2008-06-23 13:17:06] &quot;GET /static/r/toLRhQ/js/&#39;+libraryName+&#39; HTTP/1.1&quot; 404 568 - &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;1813)&quot;&lt;br /&gt;x.x.x.x - - [2008-06-23 13:17:06] &quot;GET /static/r/toLRhQ/js/&#39;+libraryName+&#39; HTTP/1.1&quot; 404 549 - &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;1813)&quot;&lt;br /&gt;x.x.x.x - - [2008-06-23 13:18:50] &quot;GET /static/r/toLRhQ/js/&#39;+libraryName+&#39; HTTP/1.1&quot; 404 549 - &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;1813)&quot;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;For a long time we just ignored them, but I finally decided to track the issue down yesterday, and found the following line in &lt;code&gt;scriptaculous.js&lt;/code&gt;:&lt;code&gt;&lt;pre&gt;&lt;br /&gt;    document.write(&#39;&amp;lt;script type=&quot;text/javascript&quot; src=&quot;&#39;+libraryName+&#39;&quot;&gt;&amp;lt;/script&gt;&#39;);&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;For whatever reason, this particular version of MSIE decides to interpret this script tag in the middle of the javascript and go trying to find a JS named &quot;&#39;+libraryName+&#39;&quot;. This is clearly incorrect behavior, and it seems like the bug was fixed in a later version of IE.&lt;br /&gt;&lt;br /&gt;Eric came up with the following clever fix:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;    document.write(&#39;&lt;&#39; + &#39;script type=&quot;text/javascript&quot; src=&quot;&#39;+libraryName+&#39;&quot;&gt;&amp;lt;/script&gt;&#39;);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Splitting the &#39;&lt;&#39; and the &#39;script&#39; tricks the broken version of IE into not seeing the script tag and solves the issue.&lt;br /&gt;&lt;br /&gt;Hope this is helpful to others who find these mysterious requests in their logs.</description><link>http://amiest-devblog.blogspot.com/2008/06/how-to-work-around-msie-bug-with.html</link><author>noreply@blogger.com (Todd)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-6288992900370281286</guid><pubDate>Wed, 18 Jun 2008 03:07:00 +0000</pubDate><atom:updated>2008-06-17T23:20:47.772-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">erlang</category><category domain="http://www.blogger.com/atom/ns#">list comprehensions</category><title>Automatically parallelizing list comprehensions in Erlang</title><description>This evening I got to chatting with some people on IRC about how it would be neat if Erlang had syntax to automatically parallelize a list comprehension. For those who aren&#39;t familiar with Erlang yet, here&#39;s a brief introduction:&lt;br /&gt;&lt;br /&gt;A list comprehension is a quick way of performing an operation over a list of values. For example, at the erlang prompt:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;1&gt; MyList = lists:seq(1,10).&lt;br /&gt;[1,2,3,4,5,6,7,8,9,10]&lt;br /&gt;2&gt; [X * 2 || X &lt;- MyList].&lt;br /&gt;[2,4,6,8,10,12,14,16,18,20]&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;For those familiar with Python list comprehensions, this is equivalent to &lt;code&gt;[x * 2 for x in range(1,11)]&lt;/code&gt;. It&#39;s also just like the &lt;code&gt;map&lt;/code&gt; operator common in pretty much every functional language. In both Python and Erlang you can get a bit more complicated:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;3&gt; [X * 2 || X &lt;- MyList, X rem 2 == 1]. %% Filter out the odd numbers from the list&lt;br /&gt;[2,6,10,14,18]&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;or even take the cartesian product of several lists in the same list comprehension:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;4&gt; [{X, Y, X * Y} || X &lt;- lists:seq(1,3), Y &lt;- lists:seq(1,3)].&lt;br /&gt;[{1,1,1},&lt;br /&gt; {1,2,2},&lt;br /&gt; {1,3,3},&lt;br /&gt; {2,1,2},&lt;br /&gt; {2,2,4},&lt;br /&gt; {2,3,6},&lt;br /&gt; {3,1,3},&lt;br /&gt; {3,2,6},&lt;br /&gt; {3,3,9}]&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;strong&gt;Now, back to the interesting part.&lt;/strong&gt; Everyone talks about how Erlang is so easy to make concurrent. But if we add the &lt;code&gt;self()&lt;/code&gt; function, which returns the current running process id, to the output of the list comprehension we see that it is not parallelized:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;5&gt; [{self(), X, Y, X * Y} || X &lt;- lists:seq(1,3), Y &lt;- lists:seq(1,3)].&lt;br /&gt;[{&lt;0.31.0&gt;,1,1,1},&lt;br /&gt; {&lt;0.31.0&gt;,1,2,2},&lt;br /&gt; {&lt;0.31.0&gt;,1,3,3},&lt;br /&gt; {&lt;0.31.0&gt;,2,1,2},&lt;br /&gt; {&lt;0.31.0&gt;,2,2,4},&lt;br /&gt; {&lt;0.31.0&gt;,2,3,6},&lt;br /&gt; {&lt;0.31.0&gt;,3,1,3},&lt;br /&gt; {&lt;0.31.0&gt;,3,2,6},&lt;br /&gt; {&lt;0.31.0&gt;,3,3,9}]&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;All of the results were computed in the same process.&lt;br /&gt;&lt;br /&gt;Handily, Erlang provides a way of inserting user code in between the parser and the compiler in the form of &lt;em&gt;parse transforms&lt;/em&gt;. A parse transform is specified in the compile options for a module and can make arbitrary modifications to the abstract syntax tree of an Erlang program before the compiler gets to it, with the important caveat: &quot;programmers are strongly advised not to engage in parse transformations and no support is offered for problems encountered.&quot; Everyone knows caveats are lame, so I went ahead and built a parse transform. Here&#39;s example usage:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;-module(test).&lt;br /&gt;-compile({parse_transform, plc}).&lt;br /&gt;-export([test/0]).&lt;br /&gt;&lt;br /&gt;test() -&gt;&lt;br /&gt;    Result = plc:lc([{self(), A, B, C} || A &lt;- lists:seq(1,2),&lt;br /&gt;                                  B &lt;- lists:seq(3,4),&lt;br /&gt;                                  C &lt;- lists:seq(5,6),&lt;br /&gt;                                  A * B &lt; 5&lt;br /&gt;                                 ]),&lt;br /&gt;    io:format(&quot;result: ~p~n&quot;, [Result]).&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Output:&lt;code&gt;&lt;pre&gt;&lt;br /&gt;result: [{&lt;0.3145.0&gt;,1,3,5},&lt;br /&gt;         {&lt;0.3146.0&gt;,1,4,5},&lt;br /&gt;         {&lt;0.3147.0&gt;,1,3,6},&lt;br /&gt;         {&lt;0.3148.0&gt;,1,4,6}]&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;We can see that the list comprehension has been performed in parallel this time - each result element has a different value of &lt;code&gt;self()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Want to check it out? Clone the &lt;a href=&quot;http://github.com/toddlipcon/plc/tree/master&quot;&gt;git repo on github&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;This probably doesn&#39;t work that well. Don&#39;t use it on production software. Unless you want to test it thoroughly first.&lt;/b&gt;</description><link>http://amiest-devblog.blogspot.com/2008/06/automatically-parallelizing-list.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-9175967807397897695</guid><pubDate>Thu, 29 May 2008 23:46:00 +0000</pubDate><atom:updated>2008-05-29T19:48:07.559-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">statistics</category><title>Confidence intervals for Jaccard Similarity?</title><description>Hoping that someone is googling for the right terms here:&lt;br /&gt;&lt;br /&gt;Anyone out there know how to calculate a confidence interval around an estimate of the Jaccard similarity coefficient?&lt;br /&gt;&lt;br /&gt;For Pearson correlation you can use Fisher&#39;s Z-prime Transformation, but I can&#39;t quite figure a principled way of doing the same for Jaccard similarity.</description><link>http://amiest-devblog.blogspot.com/2008/05/confidence-intervals-for-jaccard.html</link><author>noreply@blogger.com (Todd)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-4117450099475067565</guid><pubDate>Fri, 16 May 2008 16:52:00 +0000</pubDate><atom:updated>2008-05-16T12:57:30.424-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">erlang</category><category domain="http://www.blogger.com/atom/ns#">facebook</category><category domain="http://www.blogger.com/atom/ns#">thrift</category><title>FB Engineering blog post on Facebook Chat</title><description>Eugene at Facebook posted an &lt;a href=&quot;http://www.facebook.com/note.php?note_id=14218138919&quot;&gt;interesting article&lt;/a&gt; about the technology behind the new Facebook Chat. This new service has large parts written in Erlang and communicates with the rest of the system using the Thrift bindings Amie Street and Facebook have been collaborating on for the last couple of months.&lt;br /&gt;&lt;br /&gt;The good news for us: our thrift bindings are pretty much guaranteed to be stable and leak/bug free now that they&#39;re used for millions of messages/second over at FB.&lt;br /&gt;&lt;br /&gt;If you&#39;re interested, check out over at the &lt;a href=&quot;http://thrift-git.thruhere.net/gitweb/?p=thrift.git;a=shortlog;h=refs/heads/pri/eletuchy/new_erl&quot;&gt;thrift git repository&lt;/a&gt;</description><link>http://amiest-devblog.blogspot.com/2008/05/fb-engineering-blog-post-on-facebook.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-4026469256040989828</guid><pubDate>Tue, 13 May 2008 05:19:00 +0000</pubDate><atom:updated>2008-05-13T01:28:38.419-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">erlang</category><category domain="http://www.blogger.com/atom/ns#">garbage collection</category><category domain="http://www.blogger.com/atom/ns#">rex</category><title>Forcing a process to garbage collect in Erlang</title><description>We upgraded our dynamic pricing service tonight with a new version of thrift, so I was checking &lt;code&gt;top&lt;/code&gt; to make sure everything was cool a few hours later. I noticed that one of the pricers was using 1.1G of RAM - significantly more than I&#39;d ever seen it using before. Figuring it was a memory leak, I started a console node and connected it to the erlang cluster:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;amiest@app2:~$ erl -name console&lt;br /&gt;Erlang (BEAM) emulator version 5.5.2 [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]&lt;br /&gt;&lt;br /&gt;Eshell V5.5.2  (abort with ^G)&lt;br /&gt;(console@app2.prod.amiestreet.com)1&gt; P = pricer@app2.prod.amiestreet.com. &lt;br /&gt;&#39;pricer@app2.prod.amiestreet.com&#39;&lt;br /&gt;(console@app2.prod.amiestreet.com)2&gt; net_adm:ping(P).&lt;br /&gt;pong&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;First step of diagnostics was to fire up etop with &lt;code&gt;etop:start([{node, P}]).&lt;/code&gt; This showed that the process count was remaining stable at an appropriate number -- we&#39;d had a bug with a process leak once before but it didn&#39;t seem to be the cause this time. The amount of RAM used by processes seemed pretty high though. Next step:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;(console@app2.prod.amiestreet.com)4&gt; rpc:call(P, shell_default, i, []).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This is equivalent to running the &lt;code&gt;i()&lt;/code&gt; command on the remote node, and shows all the running processes along with some info.&lt;br /&gt;&lt;br /&gt;This printed out something useful - the &lt;code&gt;rex&lt;/code&gt; process was using almost 900MB of RAM for no apparent reason. I&#39;d never heard of &lt;code&gt;rex&lt;/code&gt;, but evidently it handles remote execution from other languages, and possibly RPC as well. Checking on some other erlang nodes I saw that &lt;code&gt;rex&lt;/code&gt; usually only used a few hundred KB.&lt;br /&gt;&lt;br /&gt;After much googling, I came across &lt;a href=&quot;http://forum.trapexit.org/mailinglists/viewtopic.php?p=1476&amp;sid=39a14a9e76ffade1e1d03cadf8b11b0a&quot;&gt;this article&lt;/a&gt; which is my only plausible explanation for how &lt;code&gt;rex&lt;/code&gt; got so big -- the Erlang GC doesn&#39;t run on a process if the process isn&#39;t doing any work.&lt;br /&gt;&lt;br /&gt;The solution? &lt;code&gt;rpc:call(P, erlang, garbage_collect, [pid(5038,10,0)]).&lt;/code&gt; (5038.10.0 was the pid shown by i()). This kicked the memory usage back down where it should be.</description><link>http://amiest-devblog.blogspot.com/2008/05/forcing-process-to-garbage-collect-in.html</link><author>noreply@blogger.com (Todd)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-2114245874081724046</guid><pubDate>Fri, 02 May 2008 16:49:00 +0000</pubDate><atom:updated>2008-05-02T13:00:11.331-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">erlang</category><category domain="http://www.blogger.com/atom/ns#">io_lib_pretty</category><category domain="http://www.blogger.com/atom/ns#">records</category><title>io_lib_pretty - a nice secret module</title><description>There are some modules in the erlang stdlib that aren&#39;t exactly advertised, but are quite useful. My newest discovery is &lt;code&gt;io_lib_pretty&lt;/code&gt;. It hasn&#39;t got a manpage, but there are some docs if you &lt;code&gt;less `locate io_lib_pretty.erl`&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;io_lib_pretty&lt;/code&gt; is the module used by the shell to print records in a nicely formatted way. This isn&#39;t possible using plain &lt;code&gt;io:format&lt;/code&gt; but can make program output a lot nicer.&lt;br /&gt;&lt;br /&gt;Take for example a logging program that deals with records that look like this:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;5&gt; L = #logMessage{actor=23507, server_ip = &lt;&lt;123,234,123,234&gt;&gt;}.&lt;br /&gt;#logMessage{actor = 23507,&lt;br /&gt;            server_ip = &lt;&lt;&quot;{\352{\352&quot;&gt;&gt;,&lt;br /&gt;            timestamp = undefined,&lt;br /&gt;            level = undefined,&lt;br /&gt;            log_filename = undefined,&lt;br /&gt;            message = undefined}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;If you just try to print it out, you get:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;7&gt; io:format(&quot;Logged: ~p&quot;, [L]).&lt;br /&gt;Logged: {logMessage,23507,&lt;&lt;&quot;{\352{\352&quot;&gt;&gt;,undefined,undefined,undefined,undefined}ok&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Pretty useless output.&lt;br /&gt;&lt;br /&gt;Using &lt;code&gt;io_lib_pretty&lt;/code&gt; you can get:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;9&gt; io:format(io_lib_pretty:print(L, fun(logMessage, 6) -&gt; [actor, server_ip, timestamp, level, log_filename, message] end)).&lt;br /&gt;#logMessage{actor = 23507,&lt;br /&gt;            server_ip = &lt;&lt;&quot;{\352{\352&quot;&gt;&gt;,&lt;br /&gt;            timestamp = undefined,&lt;br /&gt;            level = undefined,&lt;br /&gt;            log_filename = undefined,&lt;br /&gt;            message = undefined}ok&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Just like the shell. I listed the record information manually in the function above, but you can easily use the &lt;code&gt;record_info&lt;/code&gt; macro to accomplish the same without code duplication. Or even easier, use the &lt;a href=&quot;http://www.trapexit.org/forum/viewtopic.php?t=6385&amp;sid=a64a45192821687eddb69fe3ae466383&quot;&gt;exprecs&lt;/a&gt; parse transform (pretty printing example available there).&lt;br /&gt;&lt;br /&gt;Next time: how to load record definitions dynamically at runtime.</description><link>http://amiest-devblog.blogspot.com/2008/05/iolibpretty-nice-secret-module.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-1728571843783895949</guid><pubDate>Tue, 22 Apr 2008 02:10:00 +0000</pubDate><atom:updated>2008-04-21T22:11:54.145-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">cdn</category><title>Now using a CDN</title><description>I just pushed a change that enables CDN delivery of most of our static content (except for the music itself... for now). In theory it should make browsing the site a bit quicker, especially for those users not in the northeastern US.&lt;br /&gt;&lt;br /&gt;If you happen to read this and notice any difference, comment below!</description><link>http://amiest-devblog.blogspot.com/2008/04/now-using-cdn.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-29544026.post-6413190173750645517</guid><pubDate>Sat, 12 Apr 2008 23:01:00 +0000</pubDate><atom:updated>2008-04-12T21:36:57.770-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">explain</category><category domain="http://www.blogger.com/atom/ns#">index</category><category domain="http://www.blogger.com/atom/ns#">mysql</category><title>EXPLAIN everything, part 2</title><description>I &lt;a href=&quot;http://amiest-devblog.blogspot.com/2008/03/always-explain-your-queries.html&quot;&gt;previously wrote&lt;/a&gt; a post urging people trying to optimize their database usage to run the &quot;EXPLAIN&quot; command on everything. This is easy advice to ignore in the case of simple queries, but even the simple queries can be big performance problems if you miss an important detail.&lt;br /&gt;&lt;br /&gt;The other day, a friend was complaining of slow queries and was looking for some help fixing them. The first step we took was to take the &quot;problem page&quot; and enable debug output that printed each query that was run along with the number of milliseconds each took. If you don&#39;t have a facility for easily doing this (at the very least on a staging or development server) then you are essentially wandering in the dark for optimization.&lt;br /&gt;&lt;br /&gt;Looking at the debug output, we found something surprising. The slowest query on the page was the seemingly innocuous:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;SELECT `User`.`id` FROM `users` AS `User` WHERE `opensocial_id` = 219771253 LIMIT 1;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;My friend was sure there was an index on &lt;code&gt;User.opensocial_id&lt;/code&gt; yet the debug output showed that it took more than a second. With an index, this should take less than a millisecond. I asked him to run an &lt;code&gt;EXPLAIN&lt;/code&gt; on it, and we saw:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;mysql&gt; EXPLAIN SELECT `User`.`id` FROM `users` AS `User` WHERE `opensocial_id` = 2778153 LIMIT 1;&lt;br /&gt;+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+&lt;br /&gt;| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra       |&lt;br /&gt;+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+&lt;br /&gt;|  1 | SIMPLE      | User  | ALL  | opensocial_id | NULL | NULL    | NULL | 272877 | Using where |&lt;br /&gt;+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;The entry in the &lt;code&gt;possible_keys&lt;/code&gt; column confirmed that there indeed was an index on &lt;code&gt;opensocial_id&lt;/code&gt;. However, &lt;code&gt;NULL&lt;/code&gt; in the &lt;code&gt;key&lt;/code&gt; column meant that mysql was deciding the &lt;code&gt;opensocial_id&lt;/code&gt; key was either unusable or didn&#39;t have good enough selectivity to choose over a full table scan. The high value in the &lt;code&gt;rows&lt;/code&gt; column along with &lt;code&gt;Using where&lt;/code&gt; under &lt;code&gt;Extra&lt;/code&gt; indicated that mysql was reading through every row in the table, running a comparison, and outputting those rows for which the condition matched.&lt;br /&gt;&lt;br /&gt;So, the next question was &lt;i&gt;why&lt;/i&gt; mysql was deciding not to use the index for this query. Doing a &lt;code&gt;SHOW CREATE TABLE User&lt;/code&gt; revealed that the &lt;code&gt;opensocial_id&lt;/code&gt; column was of type &lt;code&gt;varchar(30)&lt;/code&gt;. Because the column was a &lt;code&gt;varchar&lt;/code&gt;, mysql couldn&#39;t use an index on it to do a comparison against a numeric query. You can see the reason for&lt;br /&gt;this:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;mysql&gt; select &quot;0234&quot; = 234\G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;&quot;0234&quot; = 234: 1&lt;br /&gt;&lt;br /&gt;mysql&gt; select &quot;234.0&quot; = 234\G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;&quot;234.0&quot; = 234: 1&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;For any given numeric value in the query, there are several varchar representations that are &quot;equal&quot; to it (shown as value 1 above). As such, there is no way for mysql to do an index lookup on a varchar column to satisfy an equality condition against a numeric constant.&lt;br /&gt;&lt;br /&gt;One easy solution would be to change the &lt;code&gt;varchar(30)&lt;/code&gt; to a numeric type. Unfortunately, it turns out that opensocial user identifiers are not simple 64-bit numeric values -- depending on the opensocial platform provider they are sometimes zero-padded, sometimes not, etc. So, using a &lt;code&gt;bigint unsigned&lt;/code&gt; was not an option.&lt;br /&gt;&lt;br /&gt;What was the solution, then? We simply added quotes to the query:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;SELECT `User`.`id` from `users` as `User` WHERE `opensocial_id` = &#39;23424234&#39; LIMIT 1;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This made the equality comparison between two varchars, and the index was used. The query now runs consistently in less than a few milliseconds.&lt;br /&gt;&lt;br /&gt;In summary, &lt;code&gt;EXPLAIN&lt;/code&gt; everything! Even the queries that look incredibly simple can be incredibly slow if they&#39;re not using the index you think they are.</description><link>http://amiest-devblog.blogspot.com/2008/04/explain-everything-part-2.html</link><author>noreply@blogger.com (Todd)</author><thr:total>0</thr:total></item></channel></rss>