Paul O’Shannessy - blah. blah. blah.2016-07-04T17:41:09-07:00https://zpao.com/feeds/atomPaul O’Shannessyzpaohttps://feedburner.google.comThis is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.Do We Need Node?2013-11-12T00:00:00-08:00https://zpao.com/posts/do-we-need-node<p>Lately I&rsquo;ve been thinking a lot about JS modules and the different implementations of module loaders. At the end of the day we&rsquo;ve all mostly settled on CommonJS, but even then we have our rough patches supporting AMD, &ldquo;pure&rdquo; <code class="prettyprint">require</code>, and global script tags. There are tools to make all of this relatively painless, but I&rsquo;m pretty excited for a future where we don&rsquo;t need any of it.</p>
<p>ES6 will hopefully bring with it modules in some form. Last I heard, <a href="http://twitter.com/littlecalculist">Dave Herman</a> and others really want to push it through, though it&rsquo;s an understandably difficult thing to push into the language, especially now. Languages like Python and Ruby have had this sort of capability from the beginning. Hell, even C had the ability to import into scope, even if it is kludgy. So I have no doubt we will have sane support for modules across modern JS engines in the next 2 years.</p>
<p>Working from that assumption… I have to ask, do we really need Node anymore? Node has baggage. It&rsquo;s tightly tied to a single JS engine, which makes it next to impossible for anybody to compare JS engines outside of the browser. V8 may have been the right choice for Ryan Dahl to make at the time, <em>a lot</em> of that had to do with the C++ API, but is it still the best engine today? In 2 years? Node has it&rsquo;s own standard library on top of the JS standard library. It <a href="http://nodejs.org/docs/latest/api/globals.html">adds globals</a> to your scripts. Some are there to make CommonJS work (<code class="prettyprint">require</code>, <code class="prettyprint">module</code>, <code class="prettyprint">exports</code>, which are actually local to each module but still considered &ldquo;global&rdquo;). Other globals are there to make scripting easier (e.g. <code class="prettyprint">__dirname</code> is not unusual for scripting languages to have). There&rsquo;s only 1 really odd one out and that&rsquo;s <code class="prettyprint">Buffer</code>. It may be useful, but it really has no place in the global scope. With a large portion of Node&rsquo;s API written in JS, why can&rsquo;t we ship each of those as a standalone module/package? We already mostly use these APIs by requiring them (<code class="prettyprint">require(&#39;fs&#39;)</code>).</p>
<p>I think we&rsquo;ll always need a way to package and distribute modules. NPM has proven how valuable that is. Look around - Ruby has <a href="http://rubygems.org/">rubygems</a>, Python has <a href="https://pypi.python.org/pypi">PyPI</a>, Objective-C has <a href="http://cocoapods.org/">CocoaPods</a>. The thing to note here is that these are <em>language</em> based and not built around an additional layer on top of a language. When you look at gems built for Ruby on Rails, they are still distributed the same way, they just have different dependencies. Going further, there are multiple interpreters for some of these languages. Ruby has MRI, JRuby, and Rubinius (and others); Python has CPython and PyPy (and likely others). For the most part these are all interchangeable (you run into issues with binary compatibility, e.g., the sqlite gem isn&rsquo;t compatible with JRuby).</p>
<p>So what do I want? I want a world where the core JS engine is swappable. Maybe I&rsquo;m deploying on an architecture not supported by V8 (Node on SPARC came up while working on SpiderNode). Maybe my employer only wants to use the JVM. Or maybe Microsoft can get some performance wins by using Chakra for Windows Azure. Back to modules, I don&rsquo;t want to get rid of npm. Or maybe I do and I want something that only supports ES6+ modules.</p>
<p>I think Node and npm have been forces of awesome over the past few years and there is no doubt they have helped propel JavaScript forward, but I think we&rsquo;re outgrowing them. There are lots of things to figure out to replace <code class="prettyprint">node</code> with <code class="prettyprint">js</code>, but maybe we should start thinking about it.</p>
<p>Just imagine: <code class="prettyprint">#!/usr/bin/env js</code></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/aDn-W_76gIM" height="1" width="1" alt=""/>This is some good SHIT2013-10-03T14:42:00-07:00https://zpao.com/posts/this-is-some-good-shit<p>It&rsquo;s been a while since <a href="/posts/this-is-very-good-position">I last wrote about recruiters</a>, but when I saw a LinkedIn email with the subject &ldquo;This is some good S**T&rdquo;, I knew it would be good&hellip;</p>
<blockquote>
<p>Hi Paul,</p>
<p>This is some good S*<em>T
Every manager and candidate I talk to says they want PASSION in the people they hire, the people they work with, and the position they hold. But when I actually speak with an individual who can CONVEY that passion and not just mouth the words, it’s a real treat. So I’m talking to this manager, and when we challenge her on the passion part, man did she go off. I mean wow. The descriptions are basically the same. RubyRubyRubyRuby. Ruby Tuesday, Ruby will you be mine, Jack Ruby, Rub on rails, Ruby don’t bring your love to town, Ruby Red. But what you will be doing, what you will be working on, what you will discover, what you will learn…Its impossible to convey the excitement this person displayed, the descriptions she gave, the PASSION she felt for her company and product. Really, you HAVE tow work her. Please call or send resume to :<a href="mailto:joseph@rgatech.com">joseph@rgatech.com</a>; 415-951-8051 to get hooked up. Not everyone will qualify, but as she said “S</em>*T, its worth a conversation!!!” I LOVE this woman!</p>
</blockquote>
<p>My response:</p>
<blockquote>
<p>This is the worst recruiter email I&rsquo;ve gotten in a while.</p>
<ol>
<li>&ldquo;This is some good S**T&rdquo; - Are you fucking serious?</li>
<li>This whole thing reads like you&rsquo;re trying to sell me drugs, not a job.</li>
<li>Do you really expect somebody else to be excited by this? There&rsquo;s nothing in here that says anything about the job.</li>
<li>Spelling and grammer mistakes.</li>
</ol>
<p>Don&rsquo;t contact me again.</p>
</blockquote>
<hr>
<p><strong>Edit:</strong> yes, I misspelled &ldquo;grammar&rdquo;. And then I learned about <a href="http://en.wikipedia.org/wiki/Muphry%27s_law">Muphry&rsquo;s Law</a>.</p>
<p>Joe noticed too and responded with a single word email:</p>
<blockquote>
<p>grammar</p>
</blockquote>
<p>Touché.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/txOWtv4_y4E" height="1" width="1" alt=""/>Adding Line Highlights to Markdown Code Fences2013-05-10T00:00:00-07:00https://zpao.com/posts/adding-line-highlights-to-markdown-code-fences<p>One thing I needed recently was an unobtrusive way to highlight lines of code, while keeping it readable (and of course, inside Markdown). The main use case I wanted it for is to highlight changed lines of code inside a tutorial. I think this is a fairly common case, and if your code blocks contain more than 3 lines of code, it&rsquo;s really helpful for the reader.</p>
<p>I didn&rsquo;t find any flavor of Markdown that let me do this, so I figured I would build on what I think is the best variant - <a href="https://help.github.com/articles/github-flavored-markdown">GitHub Flavored Markdown</a>. Code fences are already a non-standard (but super common) feature that GitHub uses, and they&rsquo;ve also added in syntax highlighting using <a href="http://pygments.org/">Pygments</a>. Pygments already has the ability to highlight lines, so all we need is a way to pass that through.</p>
<p>I came up with this syntax: <code class="prettyprint">{1,3,8-12}</code>. It&rsquo;s simple and let&rsquo;s you express individual lines and ranges with ease. It shouldn&rsquo;t conflict with any lexer name you might need to pass to Pygments (or highlighter of choice). Here&rsquo;s what it looks like in more context:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">```javascript{1,3,8-12}
</code></pre></div>
<p>And a full working example:</p>
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// This is nonsense sample code</span>
<span class="kd">var</span> <span class="nx">sample</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;sample&#39;</span><span class="p">);</span>
<span class="hll"><span class="nx">sample</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span><span class="hll"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;This is a silly place.&#39;</span><span class="p">);</span>
</span><span class="hll"><span class="p">});</span>
</span></code></pre></div>
<p>I would love to see this (or a similar) syntax make it&rsquo;s way into GFM, and maybe get support in some of the Markdown parsers as another extension. I might start hacking on that soon, but in the mean time, if you want to add support for this to your Jekyll + Redcarpet + Pygments site (and are generating your own <code class="prettyprint">HTML</code> because GitHub won&rsquo;t run your code), here&rsquo;s a file you can drop into <code class="prettyprint">_plugins</code> and go (only tested with Jekyll 1.0+):</p>
<script src="https://gist.github.com/zpao/5557101.js"></script>
<img src="http://feeds.feedburner.com/~r/zpao/~4/gkI3qwo8eP8" height="1" width="1" alt=""/>Retiring Yell at the TV2013-05-04T15:10:00-07:00https://zpao.com/posts/retiring-yell-at-the-tv<p>4 years ago (holy shit!) I <a href="/posts/yell-at-the-tv">launched</a> a little project called <a href="http://yellatthetv.com">Yell at the TV!</a>. Up until recently, I&rsquo;d mostly forgotten about it, but then I got several emails asking for me to remove some tweets. I&rsquo;d assumed the site just stopped working at some point but apparently not.</p>
<p>For the past 4 years, it&rsquo;s been slowly slurping up tweets with a few searches (most of which probably failed). It was running on Dreamhost shared hosting, on an ancient version of Rails, using SQLite. It had a <em>1.7GB</em> production.sqlite. For any number of reasons the site should have stopped working a while ago, but it kept chugging. It was <em>sloooooooooooooooow</em> but Google stuck it out and kept scraping.</p>
<p>At the end of the day, I collected 7,240,187 tweets from 3,224,219 users. I only built in 21 shows and ended up with data about 2,441 episodes of those shows. The data collection and episode classification was pretty dumb, so I know not all of these tweets were really about the TV show or episode I assumed they were.</p>
<p>Given the pervasion of Twitter and #hashtags on TV, I still think that there&rsquo;s an experience to explore around this. I would love to see more metadata attached to tweets so somebody could build an experience much like <a href="http://soundcloud.com">SoundCloud</a> for video streaming. There&rsquo;s only so much you can get humans to encode machine-parsable data and still convey something valuable for humans in 140 characters. You can see Twitter trying to do this with <a href="https://music.twitter.com/">#Music</a>, so we&rsquo;ll see if they decide to do something for video too.</p>
<p>Anyway, all data has been removed from the site. I may resurrect it in some way if I ever find the time, though honestly just searching Twitter is probably good enough.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/_MmAd579TTU" height="1" width="1" alt=""/>24 Hours of Android2013-04-20T00:00:00-07:00https://zpao.com/posts/24-hours-of-android<p>Yesterday I picked up an <a href="http://www.htc.com/us/smartphones/htc-first/">HTC First</a> with <a href="https://www.facebook.com/home">Facebook Home</a> and have been using it almost exclusively. This is my second Android device (I had a Samsung Galaxy Tab at Mozilla for a little while) but the first phone and first device I&rsquo;ve used with any consistency. My first smartphone was an iPhone 3G four years ago and I&rsquo;ve since owned an iPhone 4 and 5, so I&rsquo;m writing from that perspective. I am currently employed by Facebook, so I&rsquo;ll try to focus on Android itself and not go too much into Home.</p>
<p>Since this is an experiment and I haven&rsquo;t switched completely, here&rsquo;s how my current phone setup is working… iPhone 5 with my personal number forwarding to Google Voice. HTC First is my work number, but set up to use my Google Voice number. SMS/iMessage is not forwardable, so I have been carrying my iPhone with me to check those occasionally. I convinced my wife to message me via Facebook and that&rsquo;s 90% of my texting, so that&rsquo;s been good enough for the past day.</p>
<hr>
<h2>The Keyboard</h2>
<p>In a word, it&rsquo;s &ldquo;bad&rdquo;. Some of this is due to my muscle memory of key spacing on my iPhone. But far from all of it.</p>
<p>Typing an email address is fucking difficult. Let me tell you what is not a valid character in an email address: a space. Let me tell you what takes up most of the bottom row of the Android keyboard when typing an email address: the spacebar. On the right of that there&rsquo;s a tiny target for the period, which it turns out is actually necessary. So I&rsquo;ve typed a lot of &ldquo;name@email com&rdquo;. And then I&rsquo;ve needed to fix that, which means trying to get the caret right after that space, but that whole process is pretty bad too, so I usually fuck that up on my first try.</p>
<p>Also, did you know you can crash the keyboard? And then you can&rsquo;t get it back without restarting the phone… yup.</p>
<h2>Click Targets</h2>
<p>I noticed this a lot in the Play Store, but it seems to be a more systemic issue. Click targets are often small, often not well marked, and sometimes both.</p>
<p><img src="/img/posts/24-hours-of-android_click-target-for-ants.jpg" alt="What is this? A click target for ants!?"></p>
<h2>Browsers</h2>
<p>The First ships with Chrome, but I also installed Firefox (obviously). Being able to choose a browser has been pretty cool. Both of these are synced with my desktop browsers so passwords and history are shared (with their respective desktop counterparts, there&rsquo;s not good cross-browser sync yet that I know of). So overall my experience has been positive, except for one thing…</p>
<p>I have a bunch of tabs open because I clicked a link in Facebook or Twitter and it opened in the browser. And then I went back and opened another. Browser choice is great, but the apparent lack of one-time-use support has been annoying. iOS apps mostly solve this by having an embedded browser (which has it&rsquo;s own drawbacks).</p>
<h2>Touch Latency</h2>
<p>It&rsquo;s there. And it&rsquo;s annoying. It&rsquo;s noticeable every time I swipe. It causes accidental clicks.</p>
<h2>The Back Button</h2>
<p>As a concept, it&rsquo;s kind of cool. &ldquo;The back button always goes back to where you just were*.&rdquo; But then you read the fine print… &ldquo;* except when it doesn&rsquo;t&rdquo;. For example, if you open the Play Store and press the back button it takes you back in it&rsquo;s history stack until it has no history left, then it takes you to the launcher. If you open the Phone app and press back, it takes you to the launcher. In a day it&rsquo;s taught me that I should never completely trust it.</p>
<h2>The Menu Button</h2>
<p>I spent 5 minutes trying to figure out how to remove a phone number from a contact (which my face somehow managed to add to a random person when I tried to call the number…). Then in some other app I accidentally hit the menu button and I found a bunch of hidden stuff. Turns out that&rsquo;s how you edit a contact without accidentally calling somebody.</p>
<h2>It&rsquo;s Not All Bad</h2>
<p>Most of the apps I needed to use were available. I listend to music with Rdio, bought a movie ticket with Fandango, and rented a Zipcar. There isn&rsquo;t too much more I <em>need</em> from a phone that I couldn&rsquo;t get on Android.</p>
<p>I&rsquo;ve actually used the notification area on Android to quickly turn wifi on/off. I know iOS&rsquo;s Notification Center was pretty heavily influence by Android&rsquo;s and I would like to see more come from that.</p>
<p><a href="http://www.google.com/landing/now/">Google Now</a> seems pretty cool. But also borderline creepy. I knew Google was doing something with my search history, but &ldquo;shown before flights that you&rsquo;ve searched for&rdquo; makes it pretty obvious. It was helpful to have updating commute estimates so I could let my wife know I was going to be late. I look forward to seeing how this plays out over the next couple years.</p>
<h2>The End</h2>
<p>At the end of the day, Android would be a major upgrade from a feature phone. But to me it&rsquo;s a downgrade from iOS. I&rsquo;m not rooting my phone. I&rsquo;m not turning my phone into <a href="http://lifehacker.com/5936339/servers-ultimate-turns-your-old-android-phone-into-a-tiny-multipurpose-server">a server</a>. Don&rsquo;t get me wrong, Android is great if you want more freedom with your phone. The fact that <a href="https://www.facebook.com/home#chatheads">Chat Heads</a> can exist is really cool and I would love to see that sort of feature become available in iOS.</p>
<p>I&rsquo;m going to keep using it though &mdash; let&rsquo;s see if I feel differently in a week or so.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/X3sKNaKnPvM" height="1" width="1" alt=""/>Calling an Array of Functions in JavaScript2013-04-14T00:00:00-07:00https://zpao.com/posts/calling-an-array-of-functions-in-javascript<p>I&rsquo;ve reviewed some bits of code over the past couple months that stored functions in an array and then at some point in the future needed to call all of them. This is a very simple thing to do, but something about the code always bothered me.</p>
<p>Assuming:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kd">var</span> <span class="nx">callbacks</span> <span class="o">=</span> <span class="p">[</span>
<span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="p">},</span>
<span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="p">}</span>
<span class="p">];</span>
</code></pre></div>
<p>You end up iterating over the array and calling each function explicitly:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">callbacks</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">callback</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div>
<p>Part of the beauty of <code class="prettyprint">forEach</code> is that you can pass it a function without it having to be defined each time. So we could define a function that does what our anonymous function does for us.</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">call</span><span class="p">(</span><span class="nx">fn</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">fn</span><span class="p">();</span>
<span class="p">}</span>
<span class="nx">callbacks</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">call</span><span class="p">);</span>
</code></pre></div>
<p>This works but it feels silly. JS already has <code class="prettyprint">Function.prototype.call</code> so why should we have to write our own. Let&rsquo;s figure out if we can make <code class="prettyprint">Function.prototype.call</code> work for us&hellip;</p>
<h2>Function.prototype.call</h2>
<p>The very first thing to know about is some internal implementation details. Like most objects in JS, functions use prototypes, and so within the prototype <code class="prettyprint">this</code> refers to a particular instance. So a simplified implementation of <code class="prettyprint">call</code> would look something like this:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">call</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">thisArg</span><span class="p">,</span> <span class="nx">arg1</span><span class="p">,</span> <span class="nx">arg2</span><span class="p">,</span> <span class="p">...)</span> <span class="p">{</span>
<span class="nx">CALL_FN_WITH_SCOPE</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">thisArg</span><span class="p">,</span> <span class="nx">arg1</span><span class="p">,</span> <span class="nx">arg2</span><span class="p">,</span> <span class="p">...);</span>
<span class="p">}</span>
</code></pre></div>
<p>That&rsquo;s going to be down in native code and will of course vary by engine, but the important thing to remember is that <code class="prettyprint">this</code> is the function that gets called. There are a few more details in <a href="http://es5.github.io/#x15.3.4.4">the spec</a>.</p>
<p>The second thing to know is that you can call functions on prototypes, so long as you use them correctly. So let&rsquo;s try just calling one function.</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">callbacks</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</code></pre></div>
<p>That&rsquo;s not going to work. Effectively you&rsquo;re just calling a function that then calls <code class="prettyprint">this</code>. We might be able to write some weird code that ends up doing what we want but let&rsquo;s not. What you actually want to do is call <code class="prettyprint">Function.prototype.call</code> with a specific <code class="prettyprint">this</code> so it knows what function to actually run. Confused?</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">call</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">callbacks</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</code></pre></div>
<p>This works, but it&rsquo;s also equivalent to just saying <code class="prettyprint">callbacks[0].call()</code> so it&rsquo;s pretty bad form to do. But the point here is that we can now call a function by passing it as an argument instead of needing a proper handle to that function.</p>
<h2>Array.prototype.forEach</h2>
<p>The way <code class="prettyprint">forEach</code> works is also important to know. Go read <a href="http://es5.github.io/#x15.4.4.18">the spec</a>, or even just the <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach">MDN page</a>.</p>
<p>The key take away: the 2nd argument will be used as the <code class="prettyprint">this</code> that is accessible in the function argument. If you followed along with that chunk of the spec, you may have seen <code class="prettyprint">[[Call]]</code> — this is effectively saying that your JS is transformed into this:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">myFunction</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">thisArg</span><span class="p">,</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">index</span><span class="p">,</span> <span class="nx">array</span><span class="p">);</span>
</code></pre></div>
<p>(I say &ldquo;effectively&rdquo; because that&rsquo;s not <em>exactly</em> how it happens but if you read the spec, the result is the same, with the same possible errors.)</p>
<h2>Putting it Together&hellip;</h2>
<p>We know we want to call <code class="prettyprint">Function.prototype.call</code> and we know what function we want to be run. So the next thing to try is:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">callbacks</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">call</span><span class="p">);</span>
</code></pre></div>
<p>But that doesn&rsquo;t work. It&rsquo;s actually going to throw an error. Remember, <code class="prettyprint">this</code> is what gets called and we&rsquo;ve actually passed <code class="prettyprint">undefined</code> as this, not an item from our array. It really looks something like this:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">call</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="kc">undefined</span><span class="p">,</span> <span class="nx">callbacks</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</code></pre></div>
<p>We&rsquo;re almost there. We actually want to pass <code class="prettyprint">Function.prototype.call</code> as <code class="prettyprint">this</code> so it gets called — effectively <code class="prettyprint">Function.prototype.call.call</code>. And that in turn is passed our callback. Basically, we&rsquo;re creating a little JavaScript <a href="http://en.wikipedia.org/wiki/Matryoshka_doll">Matryoshka doll</a>. It&rsquo;s a little crazy but it works.</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">callbacks</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">call</span><span class="p">,</span> <span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">call</span><span class="p">);</span>
</code></pre></div>
<p>At the end of the day though, this isn&rsquo;t straightforward code. And in fact, <a href="http://jsperf.com/call-vs-prototype-call">it&rsquo;s quite slow</a>. So I can&rsquo;t recommend ever writing this code, though it made for an interesting thought experiment.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/IZTrgM0V47U" height="1" width="1" alt=""/>Safari 6 and a Bug with getBoundingClientRect2012-11-29T23:47:00-08:00https://zpao.com/posts/safari-6-and-a-bug-with-getboundingclientrect<p>Safari 6 shipped in July with OS X Mountain Lion and with it, a nice little WebKit bug that has some fun side effects. The bug has since been fixed in WebKit, but due to Safari&rsquo;s slow release schedule, we&rsquo;ll probably be living with this one for a while. Chrome on the other hand is unaffected (at least on the current stable release). No other browser seem to suffer from the same bug.</p>
<h2>So What Happens?</h2>
<p>Basically, if you translate a <code class="prettyprint">position:fixed</code> element, Safari doesn&rsquo;t know where it is. It <em>does</em> &ndash; Safari renders everything in the right place &ndash; it just can&rsquo;t tell you where it is. Once the element is translated, calls to <code class="prettyprint">getBoundingClientRect</code> lie. Safari basically forgets that the element was fixed and returns values that change as you scroll (sort of the opposite of what you want with <code class="prettyprint">position:fixed</code>). I&rsquo;m pretty sure the Web Inspector uses <code class="prettyprint">getBoundingClientRect</code> in the inspector too… go ahead and hover the element inside the dev tools and watch where Safari draws the bounding rectangle in content.</p>
<p><a href="/examples/safari-6-and-a-bug-with-getboundingclientrect/">I made a quick demo</a> to show what&rsquo;s happening.</p>
<h2>It Gets Better&hellip; Sike!</h2>
<p>The effect of this is cascading. Any element that is a descendent of a translated element will have its position reported incorrectly. On top of a misreported position, since Safari thinks the element is off screen, focusing it causes the page to scroll, <em>even if you can already see it</em>.</p>
<h2>What Can We Do?</h2>
<p>As far as I know, there&rsquo;s only 1 option if you need generic code: walk up the DOM when you want to know the position of an element and see if any ancestors are translated, and then when you find one use <a href="https://developer.apple.com/library/safari/documentation/AudioVideo/Reference/WebKitCSSMatrixClassReference/WebKitCSSMatrix/WebKitCSSMatrix.html"><code class="prettyprint">WebKitCSSMatrix</code></a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/aeQlJzumnkE" height="1" width="1" alt=""/>A Problem with Kellum Image Replacement2012-10-14T16:52:00-07:00https://zpao.com/posts/a-problem-with-kellum-image-replacement<p>If you&rsquo;ve ever made a website that needed to use an image instead of some text, chances are you&rsquo;ve used some image replacement technique. We all have our favorite way of doing this, but probably the most popular was the Phark technique, AKA &ldquo;-9999px hack&rdquo;, which keeps text accessible to screen readers while hiding text off screen (unless you have a ludicrously long piece of text).</p>
<p>Recently, a new technique has become popular, <a href="http://www.zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement/">touted by the venerable Zeldman</a>. It&rsquo;s a strikingly elegant solution and I quite like it.</p>
<h2>However&hellip;</h2>
<p>It does have one issue. When using the browser&rsquo;s &ldquo;find in page&rdquo; functionality, the text you&rsquo;ve hidden will become visible if it matches the text you&rsquo;re looking for. Even worse, once the text is shown it doesn&rsquo;t get hidden again when the search is complete. Try it out yourself on <a href="/examples/a-problem-with-kellum-image-replacement/">the example page</a>.</p>
<p>Like most things, there are quirks here:</p>
<ul>
<li>This bug(?) only occurs when using a positive <code class="prettyprint">text-indent</code> value.</li>
<li>Different browsers behave differently. In this case, the text doesn&rsquo;t become visible in Gecko browsers (Firefox). Webkit (Chrome, Safari) and Presto (Opera) both make the text visible. I haven&rsquo;t tested IE.</li>
</ul>
<h2>Solutions?</h2>
<p>I haven&rsquo;t figured out a way to work around this, so for the time being I&rsquo;ll likely be using the -9999px hack (or some smaller number). Or I may try another technique that sets <code class="prettyprint">font: 0/0 a</code>, which of course has it&rsquo;s own set of <a href="http://nicolasgallagher.com/another-css-image-replacement-technique/">compatibility problems</a>.</p>
<p>In case you&rsquo;re using Firefox and can&rsquo;t see the bug, here&rsquo;s what it looks like:</p>
<p><img src="/img/posts/a-problem-with-kellum-image-replacement.png" alt=""></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/ZCMBkT2dpMg" height="1" width="1" alt=""/>Making restore_on_demand Accessible2012-05-29T13:00:00-07:00https://zpao.com/posts/making-restore-on-demand-accessible<p>I know I just wrote about <a href="/posts/session-restore-changes-in-firefox-15">some changes to Session Restore coming in Firefox 15</a>, but here&rsquo;s another one&hellip;</p>
<p>Since Firefox 8, <a href="/posts/max-concurrent-tabs-is-dead/">we&rsquo;ve had a visible preference to restore tabs &ldquo;on demand&rdquo;</a>. This surfaced as a checkbox on the &ldquo;General&rdquo; preference pane. The checkbox would only be accessible if you enabled Session Restore (by setting Firefox to &ldquo;Show my windows and tabs from last time&rdquo;). This was a bit unfortunate because the preference had effects even if you didn&rsquo;t have Session Restore enabled, namely, that preference was honored when restoring a session following a crash or when returning from Private Browsing mode. In order to change the preference, Session Restore had to be enabled temporarily.</p>
<p>We&rsquo;ll be changing that in Firefox 15 now that <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=720154">bug 720154</a> landed. The checkbox has been moved from the &ldquo;General&rdquo; pane to the &ldquo;Tabs&rdquo; pane and we&rsquo;ve removed the dependency on Session Restore being enabled.</p>
<p><a href="/img/posts/originals/making-restore-on-demand-accessible.png"><img src="/img/posts/making-restore-on-demand-accessible.png" alt=""></a></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/GaQWKNh0dUc" height="1" width="1" alt=""/>Session Restore Changes in Firefox 152012-05-22T14:23:00-07:00https://zpao.com/posts/session-restore-changes-in-firefox-15<p>There are a few changes coming in Firefox 15&rsquo;s Session Restore. There are a few under the hood changes which should be transparent to anybody using the API, but there are also some changes to the format of the <code class="prettyprint">JSON</code> that is exposed.</p>
<h2>Form Data</h2>
<p>All of the changes have to do with the <code class="prettyprint">formdata</code> object that is used to store (wait for it&hellip;) form data. Historically we&rsquo;ve done our best to save the data so that when you recover from a crash or resume a session, we can do our best to get you going again. When we&rsquo;ve saved the data in the past, it was just in a flat object that looked something like this:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">&quot;formdata&quot;: {
&quot;#elementID&quot;: &quot;value for form field with id&quot;,
&quot;/xpath/string&quot;: &quot;value for form field without id&quot;
}
</code></pre></div>
<p>Starting with Firefox 15, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=697903">we&rsquo;ve broken that up a bit further</a>, with <code class="prettyprint">id</code> and <code class="prettyprint">xpath</code> keys to scoped data. The other key difference is that we no longer prepend <code class="prettyprint">#</code> to the element&rsquo;s id (it was only being used to distinguish id vs xpath). The updated format looks like this:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">&quot;formdata&quot;: {
&quot;id&quot;: {
&quot;elementID&quot;: &quot;value for form field with id&quot;
},
&quot;xpath&quot;: {
&quot;/xpath/string&quot;: &quot;value for form field without id&quot;
}
}
</code></pre></div>
<p>This was a part of making some of Session Restore more usable to other components. In this case it was something originally thought up for Sync to be able to reuse code when syncing tabs between devices.</p>
<h2>Better Restoration of <code class="prettyprint">&lt;select&gt;</code> Elements</h2>
<p><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=662743">The other change</a> will result in better restoration of <code class="prettyprint">&lt;select&gt;</code> elements. For the simple case (no <code class="prettyprint">multiple</code>) we would simply store the <code class="prettyprint">selectedIndex</code> and move on. When restoring, we would re-select that index (unless it was suddenly out of bounds). This resulted in the wrong <code class="prettyprint">&lt;option&gt;</code> being selected if <code class="prettyprint">&lt;option&gt;</code>s were added or removed. This has been a problem for years with Bugzilla where a new product or component would get added and then people would accidentally save changes to bugs and make changes they didn&rsquo;t intend.</p>
<p>So now we save the value of the selected <code class="prettyprint">&lt;option&gt;</code> and check that when restoring the form. If the value at <code class="prettyprint">selectedIndex</code> doesn&rsquo;t match what we saved, we&rsquo;ll look through all of the <code class="prettyprint">&lt;option&gt;</code>s until we find a match. It&rsquo;s a simple change but should result in more reliable form restoration.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">&quot;selectEl&quot;: 1
</code></pre></div>
<p>becomes</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">&quot;selectEl&quot;: {
&quot;selectedIndex&quot;: 1,
&quot;value&quot;: &quot;option value&quot;
}
</code></pre></div>
<h2>Backwards Compatability</h2>
<p>As with all changes in Session Restore, we&rsquo;ll be maintaining compatability with the old format for some extended period of time. We will continue to be able to read the old format, but we won&rsquo;t write it back out. If you&rsquo;re an API consumer, you should update accordingly. Extension authors should be ready to handle both formats while supporting Firefox 14 and below.</p>
<h2>Not Me!</h2>
<p>I didn&rsquo;t write code for any of this! Thanks to Andres and Bellindira from AppCoast for picking up half-written patches and taking them the rest of the way. Tim Taubert helped out a bunch with reviews too. There are other Session Restore changes that this group is working on so there&rsquo;s more to come!</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/jrGO6MD6a7s" height="1" width="1" alt=""/>Building Firefox on OS X Mountain Lion2012-05-14T00:00:00-07:00https://zpao.com/posts/building-firefox-on-os-x-mountain-lion<p>In a similar vein to <a href="/posts/building-firefox-on-os-x-lion">my article about building on 10.7</a>, here are some issues that have come up while building Firefox on 10.8. I&rsquo;ve had Mountain Lion installed for a few weeks now and while there were a few hiccups, things have been pretty smooth. Currently I have DP3 update 2 and Xcode 4.4 preview 5 installed.</p>
<h2>Xcode &amp; Command Line Tools</h2>
<p>If you&rsquo;ve installed Mountain Lion (MoLo) then you&rsquo;ve probably realized that you need to reinstall Xcode. This is available on the pre-release software page. Make sure you download &amp; install the Command Line Tools as well. I had issues installing the CL tools from within Xcode, so the separate download was necessary.</p>
<h2><code class="prettyprint">egrep</code></h2>
<p>You will likely see an error about <code class="prettyprint">egrep</code>. We have a &ldquo;fixed <code class="prettyprint">egrep</code>&rdquo; command we&rsquo;ve been using since Lion to work around an issue. It seems we no longer need to work around that issue. I have a patch in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=750574">bug 750574</a> that makes sure our workaround is only used on Lion.</p>
<h2><code class="prettyprint">clang</code> &amp; <code class="prettyprint">ccache</code></h2>
<p>I&rsquo;ve been using <code class="prettyprint">clang</code> to build Firefox for a few months now and have been using <code class="prettyprint">ccache</code> for years. While I didn&rsquo;t have any issue before, on MoLo the 2 didn&rsquo;t play together nicely. I got build errors while building Growl. Specifically, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=754988">there were issues with an (un?)expanded NSParameterAssert macro</a>. The fix is to ensure that you set the <code class="prettyprint">CCACHE_CPP2</code> environment variable to <code class="prettyprint">yes</code> (<code class="prettyprint">export CCACHE_CPP2=yes</code>). Peter Eisentraut explains why this <code class="prettyprint">ccache</code> setting works on <a href="http://petereisentraut.blogspot.com/2011/09/ccache-and-clang-part-2.html">his blog</a>. We now have a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=755145">bug on file to make this automatic</a> so you don&rsquo;t have to set environment variables to get a working build.</p>
<h2>homebrew</h2>
<p>This isn&rsquo;t directly related, but I had some issues with packages installed via <code class="prettyprint">brew</code>. In my case <code class="prettyprint">imagemagick</code> didn&rsquo;t cooperate. That&rsquo;s not required to build Firefox, but just a heads up that you may have issues. <a href="https://gist.github.com/1860902">These steps</a> got everything working for me.</p>
<h2>That&rsquo;s it</h2>
<p>There&rsquo;s a good chance that this isn&rsquo;t even relevant by the time you install 10.8. If so, then I&rsquo;ve done my job!</p>
<p>If you&rsquo;re interested in working on features for Mountain Lion, let me know or follow <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=728102">the tracking bug</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/XUEe956m8-4" height="1" width="1" alt=""/>hg amend2012-05-07T00:00:00-07:00https://zpao.com/posts/hg-amend<p>Mercurial 2.2 introduced a new <code class="prettyprint">--amend</code> option to <code class="prettyprint">commit</code>. If you&rsquo;ve ever used Git, then you are probably thinking &ldquo;finally&rdquo;. For those of you who haven&rsquo;t used it, it&rsquo;s a quick way to modify the last commit.</p>
<p>My workflow with Mercurial is quite different than my workflow with Git, so <code class="prettyprint">amend</code> is not going to be as critically important. With Git I typically just have a series of commits on a branch. With Mercurial I typically use a patch queue (because that&rsquo;s just easier with posting patches to Bugzilla). But there have been plenty of times where I&rsquo;ve <code class="prettyprint">qfinish</code>ed a patch only to realize I didn&rsquo;t update the commit message to include the reviewer. Previously this was a 3 step process to fix: <code class="prettyprint">qimport -r tip; qrefresh -e; qfinish qtip</code>). Now it&rsquo;s 1: <code class="prettyprint">hg commit --amend</code>. You can do the same with files you forgot to add.</p>
<p>I haven&rsquo;t played with it much, but the <a href="http://mercurial.selenic.com/wiki/WhatsNew#Mercurial_2.2_.282012-05-01.29">release notes</a> mention that this is a &ldquo;safe&rdquo; operation since it uses Mercurial <a href="http://mercurial.selenic.com/wiki/Phases">phases</a>. Essentially this simply stops you from editing history in patches that you&rsquo;ve already pushed to a remote repository.</p>
<p>So there you have it. And a little bonus for people who like to cut down on typing - alias the option to a new command. I&rsquo;ve been doing this with Git for ages, but now I can finally add it to my <code class="prettyprint">.hgrc</code> too:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">[alias]
amend = commit --amend
</code></pre></div><img src="http://feeds.feedburner.com/~r/zpao/~4/bORW_qFY7vQ" height="1" width="1" alt=""/>Lion Full Screen Coming to Firefox2012-03-22T00:00:00-07:00https://zpao.com/posts/lion-full-screen-coming-to-firefox<p>For the past little while, I&rsquo;ve been working on adding support for <a href="https://www.apple.com/macosx/whats-new/full-screen.html">OS X Lion&rsquo;s native Full Screen mode</a> to Firefox. This was something that others had started before Lion was even released but nobody ever finished it. Since then, every other major browser has shipped support for the feature.</p>
<p>I decided to start working on it in December since nobody else was. Having never really touched Objective C(++) or Cocoa, the task took a bit longer for me than it would have others, but now it&rsquo;s done and I have more experience with our <code class="prettyprint">widget/</code> code. At the end of the day, the changes need to hook everything up were suprisingly minimal. If you want to check out the process, the work was done in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=639705">bug 639705</a>.</p>
<p>The patches were landed the other day and are currently in <a href="http://nightly.mozilla.org">Firefox Nightly</a>. Assuming there are no major issues, this should ship in Firefox 14. Since this landed early in the release cycle, there should be plenty of time to catch any fallout. There are a few known bugs to follow up with (see below) but if you notice any other issues on the Firefox side, please <a href="https://bugzilla.mozilla.org/enter_bug.cgi?blocked=639705&amp;cc=paul%40oshannessy.com&amp;component=General&amp;op_sys=Mac%20OS%20X&amp;product=Firefox&amp;rep_platform=x86">file a new bug</a> (already setup for a new bug in Firefox:General with me CCed).</p>
<h2>Adding Support to Your Gecko Application</h2>
<p>Since the feature is enabled down in the core, it&rsquo;s now easy to support Lion Full Screen in your Gecko application. All that you need to do is add <code class="prettyprint">fullscreenbutton=&quot;true&quot;</code> to your <code class="prettyprint">&lt;window&gt;</code>. Thunderbird <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=711750">is in the process of doing this</a>. If you&rsquo;d like your application to make UI changes (beyond just titlebar hiding), the <code class="prettyprint">fullscreen</code> event is fired on the window after the transition is complete.</p>
<h2>But wait, there&rsquo;s more</h2>
<p>What I&rsquo;ve done so far is really just the baseline support. There are a few followup bugs:</p>
<ul>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=703724">support resizing content area</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=716450">figure out &lsquo;background themes&rsquo; support</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=714172">update menu with new string/shortcut</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=714186">add top padding?</a></li>
<li>and surely some other theme related tweaks</li>
</ul>
<img src="http://feeds.feedburner.com/~r/zpao/~4/HE59pzSCHTU" height="1" width="1" alt=""/>This is very good position2012-02-27T00:00:00-08:00https://zpao.com/posts/this-is-very-good-position<blockquote>
<p>Hi Paul ,</p>
<p>I hope that you are doing well. There is a position in Ebay in as Frontend Engineer. Hiring managers from two different groups are very much impressed with your profile and they want to set up telephonic talk on the phone.</p>
<p>This is very good position . So would you please send me updated copy of your resume. If you are looking for Fulltime or long term contract whatever way you are looking they can do it for you.</p>
<p>Whatever salary you are looking for that way manager is ready to pay you.</p>
<p>Please send me salary expectation and your availability as soon as possible so we can schedule your interview because manager has your profile and they are pushing me to schedule your interview as soon as possible so you will be on board immediately after clearing an interview.</p>
<p>Manager is also asking one question after reviewing your profile. So would you please give me your contact details so we can talk more about this position. He has very much hope on you.</p>
</blockquote>
<p>I understand that English is not everybody&rsquo;s first language but I expect better of somebody whose job is entirely about communication.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/7TRjJhRyoZY" height="1" width="1" alt=""/>Somebody That I Used to Know2012-02-02T00:00:00-08:00https://zpao.com/posts/somebody-that-i-used-to-know<iframe width="640" height="360" src="http://www.youtube.com/embed/d9NF2edxy-M?rel=0" frameborder="0" allowfullscreen></iframe>
<p>Somehow I&rsquo;ve been listening to <em>Somebody That I Used to Know</em> by Gotye on repeat for the past week and haven&rsquo;t gotten sick of it yet. This cover by Walk off the Earth is so excellent, not just because of how good it sounds but also because of how it was performed.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/j4_TpKay9Z8" height="1" width="1" alt=""/>What&rsquo;s the Deal With V8Monkey &amp; SpiderNode?2012-01-23T00:00:00-08:00https://zpao.com/posts/whats-the-deal-with-v8monkey-spidernode<p><strong>tl;dr</strong> Neither are being actively worked on and could use some love.</p>
<hr>
<p>After NodeConf, development of <a href="https://github.com/zpao/v8monkey">V8Monkey</a> &amp; <a href="https://github.com/zpao/spidernode">SpiderNode</a> slowed. We all got a bit burnt out in the weeks preceding NodeConf and took a little break. Shortly after, Shawn left Mozilla to work at Facebook with Rob on <em>[redacted]</em> and the little break became longer. I was in the middle of planning a wedding &amp; helping the (now-)wife with <a href="http://onetruelovevintage.com">her company</a>. Shawn &amp; Rob were busy with work and some other <a href="https://github.com/sdwilsh/tree-bot">side</a> <a href="https://github.com/mozilla/rust">projects</a>. Mozilla opened an office in SF in August, so I stopped riding the train down the peninsula with Shawn &amp; Rob as often. Long story short, we lost interest.</p>
<p>In October I pulled current mozilla-central into the V8Monkey tree &amp; tried to update from there. But some core things changed. APIs changed around Typed Arrays in SpiderMonkey. <code class="prettyprint">JSScript</code> stopped being a <code class="prettyprint">JSObject</code> which broke some of our assumptions with our implementation. I have <a href="https://gist.github.com/1665805">a patch locally</a> to try to fix those, but they&rsquo;re incomplete (it immediately segfaults). It&rsquo;s been 3 months and the JS engine doesn&rsquo;t idle, so it&rsquo;s entirely possible the world changed again.</p>
<p>SpiderNode is untouched. But Node has definitely changed - it&rsquo;s gone from 0.4.x to 0.6.x and works on Windows! It&rsquo;s now using a newer version of V8, and further, using more V8 APIs that V8Monkey hasn&rsquo;t ported. It also looks like Buffers got a pretty big overhaul (I started to merge that, but it got messy). There&rsquo;s surely some other work that needs to be done.</p>
<h2>The Future</h2>
<p>There has been <a href="https://twitter.com/#!/BrendanEich/status/158326339039010817">some mention</a> of the JS team here at Mozilla implementing the V8 API. Not me or somebody doing it in their free time, but a full-time employee. I haven&rsquo;t seen that happen, but that&rsquo;s the best possible outcome. Assuming we have 100% compatibility (which is the only target that makes sense), then the path to reviving SpiderNode from there is easy. Basically we&rsquo;d just need to fix the build system again to compile SpiderMonkey &amp; use that. Brendan has also <a href="https://twitter.com/#!/BrendanEich/status/158328492709257217">threatened to unbitrot V8Monkey</a>, but he&rsquo;s a busy guy, so we&rsquo;ll see.</p>
<p>If that doesn&rsquo;t happen, then the future is grim. I don&rsquo;t have the time or drive to do this myself. If you&rsquo;re interested in helping out though, keep reading&hellip;</p>
<h2>Want to help?</h2>
<p>Awesome! Get in touch &amp; I can help get you started. I&rsquo;m more than happy to get that going because I&rsquo;d like to see these projects live on. Keep in mind that the real work mostly happens in V8Monkey &ndash; it&rsquo;s 100% C++ and you&rsquo;re implementing one JS engine&rsquo;s API with another.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/Twjx5Yx3NME" height="1" width="1" alt=""/>And Just Like That I&rsquo;m a Firefox Peer2011-10-26T00:00:00-07:00https://zpao.com/posts/and-just-like-that-im-a-firefox-peer<p>Not-so-long story short, as of a couple weeks ago Firefox review policies changed and now I can review any code going into Firefox (<code class="prettyprint">browser/</code>)! In actuality though, if a review request came my way in an area I wasn&rsquo;t familiar with, I would just give feedback and redirect the review to somebody more familiar with that code.</p>
<p>Read up on the <a href="https://wiki.mozilla.org/Firefox/Code_Review">new Firefox review policy</a> and see <a href="https://wiki.mozilla.org/Modules/Firefox">who else can review your patches</a> to Firefox.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/tz_4tht2iOI" height="1" width="1" alt=""/>Married!2011-10-11T00:00:00-07:00https://zpao.com/posts/married<iframe src="http://player.vimeo.com/video/30352750?title=0&amp;byline=0&amp;portrait=0" width="640" height="360" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
<p>Did you know that I got married 3.5 weeks ago? Now you do! I have more to say about it all, but here&rsquo;s a short video from our awesome videographers, <a href="http://seaglasscinema.com/">Seaglass Cinema</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/F_w6zG1lngY" height="1" width="1" alt=""/>max_concurrent_tabs is Dead; Long Live restore_on_demand2011-08-17T00:00:00-07:00https://zpao.com/posts/max-concurrent-tabs-is-dead<p>Since <a href="/posts/cascaded-session-restore-a-hidden-bonus">last September</a>, you could set <code class="prettyprint">browser.sessionstore.max_concurrent_tabs</code> to 0, and you would essentially have a built-in BarTab. I slipped that in later in the Firefox 4 release cycle as a part of cascaded session restore, but it required going into <code class="prettyprint">about:config</code> and changing a preference value (or installing something like <a href="https://addons.mozilla.org/en-US/firefox/addon/bartab-lite/">BarTab Lite</a>).</p>
<p>Starting with the latest nightly (and soon to be Aurora 8), <code class="prettyprint">browser.sessionstore.max_concurrent_tabs</code> is no more. We&rsquo;re no longer allowing you to specify a specific number of tabs to restore concurrently. Instead we now allow you to either restore on demand, or use the hard-coded 3 tabs at a time value. The new preference is called <code class="prettyprint">browser.sessionstore.restore_on_demand</code>. If you had customized <code class="prettyprint">max_concurrent_tabs</code> and set it to 0, then <code class="prettyprint">restore_on_demand</code> will be migrated to true. Unlike the old preference, <code class="prettyprint">restore_on_demand</code> is exposed in the Preferences/Options dialog to make it accessible to a larger audience.</p>
<p><img src="/img/posts/restore_on_demand.png" alt=""></p>
<p>For the details, check out <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=648683">bug 648683</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/fhHoHaVXKGo" height="1" width="1" alt=""/>This is Bad Recruiting2011-08-10T00:00:00-07:00https://zpao.com/posts/this-is-bad-recruiting<p>An email came in yesterday with the subject <em>Amazing Career Opportunity Unlimited Funds!</em> looking like this:</p>
<blockquote>
<p>Hi Paul,</p>
<p>This is <em>[name]</em> from <em>[recruiting company]</em>.</p>
<p>I’m recruiting for a super HOT online company opening a west coast office in San Francisco to build new products. We are looking for top engineers (Ruby Developers and JavaScript Engineers).</p>
<p>This company is HOT and I want you to be a part of it… We have an unlimited budget! Offering you a guaranteed 20% pay raise (if not more), equity, and paid bonuses! Let’s just say this company is hotter than Google. We just hired the <em>[manager position]</em> from Google for $300K. (Seriously no money cap) we are looking for the best and will pay to get the best.</p>
<p>If you are interested and want to learn more let’s talk!</p>
<p>What is a good time and number to give you a call?</p>
</blockquote>
<p>What&rsquo;s so bad here? To me, plenty. But if you see nothing wrong then I&rsquo;ll refer you to this person and it&rsquo;s all yours.</p>
<h2>&ldquo;super HOT online company &hellip; to build new products&rdquo;</h2>
<p>AWWWWW SHIT. You&rsquo;re the same as nearly every tech company on the planet. Not only have you failed to differentiate this company from the rest of the world, you haven&rsquo;t told me who the company is or what they might be making. In order to find out if it&rsquo;s even remotely cool I have to email you (I know, that&rsquo;s what they want you to do). For somebody who hasn&rsquo;t entertained the thought of changing jobs, making me take the effort to contact you isn&rsquo;t going to happen.</p>
<p>I understand there are stealth companies out there making things. If you are one of these companies I hope that (a) you&rsquo;re hiring people you know and trust and (b) you make it clear that you&rsquo;re not ready to talk publicly about your product so I don&rsquo;t call you a shitty recruiter.</p>
<h2>&ldquo;This company is HOT&rdquo;</h2>
<p>That&rsquo;s the second time &ldquo;HOT&rdquo; was used in all caps to describe this company. I guess it&rsquo;s better than saying &ldquo;HAWT&rdquo;. Seriously though, it just looks immature and desperate.</p>
<h2>&ldquo;Let’s just say this company is hotter than Google&rdquo;</h2>
<p>Bullshit.</p>
<h2>OMG WE ARE LEAKING MONEY OUT OF OUR ASSHOLES AND MONEYMONEYMONEY</h2>
<p>There are people out there who just want to make boatloads of cash and get out. Who wouldn&rsquo;t mind boatloads of cash, especially in the bay area where shit is expensive. But you don&rsquo;t actually want those people to work for your company. If they aren&rsquo;t passionate about what they&rsquo;re making, they&rsquo;ll make a quick buck &amp; be gone fast, probably responding to another email like this. Hell, it might even be you recruiting them away.</p>
<p>I know there&rsquo;s a hiring frenzy in the SF area and in the tech industry as a whole. That&rsquo;s all the more reason to be good at recruiting and not make me call out your shenanigans. There are recruiters out there who I&rsquo;ve said more than &ldquo;No&rdquo; to because they make a proper attempt and are polite to me (<a href="/posts/on-rude-recruiters">I don&rsquo;t like rude recruiters</a>).</p>
<p>That&rsquo;s all I&rsquo;ll say. That and I&rsquo;m not looking for a new job.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/0vF6yw_1C-o" height="1" width="1" alt=""/>hg qedit2011-08-09T00:00:00-07:00https://zpao.com/posts/hg-qedit<p>Mercurial queues are still far from my ideal workflow, but they mostly <em>just work</em> so I still use them. I haven&rsquo;t gotten into qqueues because that seems like even more management I don&rsquo;t need. If I had a 17 part patch then I would probably give those a go, but I don&rsquo;t.</p>
<p>Instead I end up reordering the patches in my queue more often that I want. I run <code class="prettyprint">vim .hg/patches/series</code>, press a <code class="prettyprint">j</code>, <code class="prettyprint">k</code>, <code class="prettyprint">d</code>, &amp; <code class="prettyprint">p</code> a few times, then quit. But sometimes I forget that I&rsquo;m not at <code class="prettyprint">hg root</code> so that doesn&rsquo;t work (usually tab completion is a good indicator but then I need to <code class="prettyprint">cd</code> a bit). <a href="https://github.com/zpao/dotfiles/commit/51cdfb838c672f80db5b005eca1fe9972c23dab6">Enter <code class="prettyprint">hg qedit</code></a>.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">[alias]
qedit = !vim $(hg root)/.hg/patches/series
</code></pre></div>
<p>Just add the above to your .hgrc and you now have a new command which will pop open vim so you can reorder your patches. And of course if you want this to use your editor of choice, you can change &ldquo;vim&rdquo; to &ldquo;$EDITOR&rdquo; to make that happen.</p>
<hr>
<p>A couple people have mentioned that there are easier ways to move things around in your queue without editing your series file&hellip;</p>
<p><a href="http://www.gavinsharp.com/blog/">Gavin</a> told me about <a href="http://mercurial.selenic.com/wiki/QupExtension">qup</a>, and <a href="http://www.oxymoronical.com/">Dave</a> said that <code class="prettyprint">hg qpush --move &lt;name&gt;</code> achieves the same thing.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/Qun06kg8EiM" height="1" width="1" alt=""/>Building Firefox on OS X Lion2011-07-23T00:00:00-07:00https://zpao.com/posts/building-firefox-on-os-x-lion<p>I know there are people here at Mozilla who have been building Firefox on Lion releases for a while now, but I couldn&rsquo;t find anything that described all the problems. So here I am.</p>
<p><em><strong>TL;DR:</strong> Reinstall XCode &amp; apply a <a href="https://bugzilla.mozilla.org/attachment.cgi?id=547774">couple</a> <a href="https://bugzilla.mozilla.org/attachment.cgi?id=547889">patches</a>.</em></p>
<h2>Mercurial</h2>
<p>I had originally installed Mercurial via <code class="prettyprint">easy_install</code>, so your results may be different. Regardless it was broken. Apparently you can edit the executable and it works, but I didn&rsquo;t try. Attempting to install Mercurial again failed with <code class="prettyprint">Python headers are required to build Mercurial</code>.</p>
<p>Reinstall XCode then reinstall Mercurial and you&rsquo;re set.</p>
<h2><code class="prettyprint">make</code> Not Found</h2>
<p>Reinstalling XCode fixes that too.</p>
<h2>Build Fails with <code class="prettyprint">expected initializer before ‘NS_NORETURN’</code></h2>
<p>Your build will probably fail. The patch in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=655339">bug 655339</a> works to get past this.</p>
<h2>Build Fails with <code class="prettyprint">$MACOSX_DEPLOYMENT_TARGET mismatch</code> error</h2>
<p><code class="prettyprint">distutils.errors.DistutilsPlatformError: $MACOSX_DEPLOYMENT_TARGET mismatch: now &quot;10.6&quot; but &quot;10.7&quot; during configure</code></p>
<p>I first thought this was a problem with specifying the wrong target SDK, but I was wrong. This is apparently a python bug. <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=659881">Bug 659881</a> has more details (and a workaround patch). The bug talks about python via MacPorts, but I&rsquo;m not using MacPorts nor any non-default python installs.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/fZ2Q0zhQMgs" height="1" width="1" alt=""/>Simple Tab Stats Script2011-06-17T00:00:00-07:00https://zpao.com/posts/simple-tab-stats-script<p>My Firefox usage has always been a bit excessive. I used to open windows to group my different tasks. Then Panorama came along and I started using groups. Then I had too many groups so I started opening new windows. Luckily I set <code class="prettyprint">max_concurrent_tabs</code> to 0 so I avoid loading all of those pages at startup (<a href="/posts/cascaded-session-restore-a-hidden-bonus">it&rsquo;s that BarTab-like thing</a>).</p>
<p><img src="/img/posts/simple-tab-stats.png" alt=""></p>
<p>My curiosity got the better of me so I wrote <a href="https://gist.github.com/1020014">a little script</a> to tell me some facts about my usage. There are extensions that do some or all of this, but I didn&rsquo;t actually want to install anything, I just wanted a quick snapshot of what was up. (That said I might turn it into an <em>about:something</em> sort of extension.) You can see what it tells you - it&rsquo;s not much but it told me what I wanted to know. My usage was higher earlier today, and I&rsquo;m sure there are people who are much more abusive of Firefox, so no judging.</p>
<script src="https://gist.github.com/1020014.js?file=run-this.js"></script>
<p>Judging me on coding style? I would be. I started writing this in the error console, so I left out whitespace and used shitty variable names. Then it grew up and got all awkward.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/JZUfQH-Laow" height="1" width="1" alt=""/>SpiderNode at NodeConf 20112011-05-19T00:00:00-07:00https://zpao.com/posts/spidernode-at-nodeconf-2011<p>Two weeks ago, I traveled with Shawn and Rob to Portland for the inaugural NodeConf. To summarize: it was a great experience and a well run conference. Other people have done overviews, so I’m not going to go there, but read a few <a href="http://www.sauria.com/blog/2011/05/09/nodeconf-2011/">here</a>, <a href="http://www.claassen.net/geek/blog/2011/05/reflections-on-jsconf-and-nodeconf-by-a-language-geek.html">here</a>, and <a href="http://www.adamchristian.com/archives/10435">here</a>. I’m going to talk about SpiderNode at NodeConf instead.</p>
<h2>A Quick Aside on the State of Things</h2>
<p>We got SpiderNode running on the train ride shortly before getting on a plane to Portland. Under 24 hours before NodeConf. It didn’t pass all tests (still doesn’t) and we had to hack around Node’s Buffers pretty majorly. Ryan&rsquo;s classic <a href="https://github.com/ry/node_chat">node_chat</a> ran and that was a great state to be in going into NodeConf. As for other demos, those were written right before the presentation so they were a bit unpolished.</p>
<h2>Back to NodeConf</h2>
<p>As we&rsquo;d suspected for a while, Brendan Eich was the “Mozilla Person Secret Talk” listed on the schedule. He talked a little bit about ES.next and SpiderNode, with a couple demos. In typical Brendan fashion, it was a lot of information to get in a short period of time. If you want to see the slides, <a href="http://brendaneich.com/2011/05/mozillas-nodeconf-presentation/">Brendan has them on his blog</a>.</p>
<p>Overall, I think the reception we got was really positive. People seemed excited. Some viewed it as a way to run Node on architectures that V8 doesn’t support (before we left NodeConf I had an email from somebody telling me he had patches to get SpiderNode building on Solaris/Sparc). Others were just excited that this could open up the doors to making Node faster (more benchmarks to compete on). Other people were excited because they just really want block scoping (<code class="prettyprint">let</code>).</p>
<p>Other people weren’t so excited. And that’s fair. But there seemed to be some misconceptions about the project and why we were at NodeConf contributing to what felt a bit like disdain.</p>
<h2>Selling You</h2>
<p>There were some people who seemed convinced that we were there to sell people on using SpiderNode. I think Brendan made this pretty clear during his talk, but here it is again: we’re not trying to sell you. We don’t think you should use it right now. We’re getting closer, but it might be a little while before we suggest people use it for anything besides experimenting. We don’t pass all of the Node tests and we’re almost certainly not faster at this point.</p>
<p>I think <a href="http://brendaneich.com/2011/05/mozillas-nodeconf-presentation/">Brendan put it best</a>:</p>
<blockquote>
<p>We are not out to make a maintained, competing fork of Node, just a friendly downstream that should go away as soon as possible. We aren’t selling anything to Node users.</p>
</blockquote>
<h2>Splitting the Community</h2>
<p>The Node community is pretty awesome and we really don’t want to split it in anyway. I’m sorry that some of you felt that’s what we were doing. If that was you, I’d love to find out what you meant.</p>
<p>The only angle I can see on this one is that the JavaScript one would write using SpiderMonkey’s JS extensions wouldn’t run on normal (V8) Node. This goes back to the experiment thing. If you’re writing Node modules or code you want to share widely using the JS extensions STOP.</p>
<h2>Contributing Back</h2>
<p>I didn’t see any comments about this topic, but I wanted to make it clear that we’re most certainly going to be contributing back to Node. We created <a href="https://github.com/sdwilsh/spidernode-upstreaming">a repository</a> to start that process now. We’re waiting for somebody to handle <a href="https://github.com/joyent/node/pull/1021">this pull request</a>, which should make some uses of Buffer faster.</p>
<p>There will surely be other things that can be upstreamed outside of our use of V8Monkey (and the build system changes required to support that).</p>
<hr>
<p>I hope this clears some things up for people. Let me know if it doesn’t or you have other concerns about SpiderNode’s existence.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/qARsKDClGAg" height="1" width="1" alt=""/>About That Hybrid “V8Monkey” Engine2011-04-14T00:00:00-07:00https://zpao.com/posts/about-that-hybrid-v8monkey-engine<p>I&rsquo;ve sort of been working on this thing&hellip;</p>
<p>Several weeks ago I was curious about why there was no implementation of <a href="http://nodejs.org/">Node.js</a> using the <a href="https://developer.mozilla.org/En/SpiderMonkey">SpiderMonkey</a> JavaScript engine (the one we use in Firefox). So <a href="https://twitter.com/#!/zpao/status/42780850177327105">I tweeted</a> about it and several people said they wanted such a thing and would help work on it.</p>
<p>After some poking around the source, we realized that Node was tied pretty closely to <a href="http://code.google.com/apis/v8/">V8</a>, and there really wouldn&rsquo;t be any way to use SpiderMonkey without ripping Node apart and rebuilding it. Not only would that suck now, but it would likely suck long into the future as Node gets updated. This port would fall behind and nobody wants that.</p>
<h2>V8Monkey</h2>
<p>So we decided that we would implement the V8 API on top of SpiderMonkey. That way we can just plug our work into Node, and it would &ldquo;just work&rdquo;. We&rsquo;ve been chugging along on this project and have made some great progress. Thanks to John Ford we even have an automated build system running all of our tests on every checkin.</p>
<p>The JS team at Mozilla is also really interested in just having this API around. It has potential for other projects like this, but also raises awareness of API differences and might help push forward changes to the SpiderMonkey API. We&rsquo;ve already pushed for additions to the SpiderMonkey API (for example, there was previously no exposed API to check <code class="prettyprint">==</code>, only <code class="prettyprint">===</code>). There have also been discussions about turning the SpiderMonkey API into a C++ API (not just C).</p>
<p>It also turns out that we&rsquo;re not the first people to go down this track. There&rsquo;s a team at Yahoo! who is very interested in Node and even did a very similar project. They even put the <a href="https://github.com/bfrancojr/v8monkey/commit/95464c1ccc07e2ab10ba637de3938b5dcd924403">code out there to prove it</a> and it&rsquo;s been a helpful reference for us. They stopped short to get Node mostly running, while our goal is a bit more ambitious and implement the whole V8 API.</p>
<h2>SpiderNode</h2>
<p>SpiderNode is what we&rsquo;re calling our fork of Node. Once we have our V8 binding working, we&rsquo;ll shift our work over here and focus on integrating SpiderMonkey into the Node build system. Ideally we&rsquo;d love to get this upstreamed and give Node developers a choice.</p>
<p>We think V8 is great and the fact that Node has become so widely used is a testament to that. But we also think there&rsquo;s room for competition here. Browser based competition is old-hat. Let&rsquo;s move this battle to the servers :)</p>
<p>With some hackery from John, we now have a way to build SpiderNode. As of Tuesday <code class="prettyprint">node.cc</code> compiles (OMG AWESOME) but that&rsquo;s it.</p>
<h2>Can You Help?</h2>
<p>Absolutely. The code for both <a href="https://github.com/zpao/v8monkey">v8monkey</a> and <a href="https://github.com/zpao/spidernode">SpiderNode</a> are on GitHub for now. We have a <a href="https://github.com/zpao/v8monkey/wiki/Hacking">&ldquo;hacking&rdquo; wiki page</a> there, as well as a general <a href="https://github.com/zpao/v8monkey/wiki/TODO">TODO page</a>.</p>
<p>We also chat a lot on IRC: <a href="irc://irc.mozilla.org/spidernode">#spidernode on irc.mozilla.org</a>.</p>
<h2>It&rsquo;s Not Just Me</h2>
<p>That&rsquo;s for damn sure. <a href="https://twitter.com/robarnold">Rob Arnold</a> and <a href="https://twitter.com/sdwilsh">Shawn Wilsher</a> have been doing most of the heavy lifting. Rob has done some work on SpiderMonkey in a past life and is really good at this sort of language stuff. Shawn is also really smart and definitely no stranger to using SpiderMonkey. This project would be nowhere without these guys. <a href="https://twitter.com/john_h_ford">John Ford</a> set up a buildbot for us, which has been incredibly helpful for catching all the tests I break. Having a build engineer helping out has been really great.</p>
<p><a href="https://twitter.com/BrendanEich">Brendan Eich</a> (you may have heard of him) said he&rsquo;s going to start contributing. My intern <a href="http://twitter.com/mehdiisdumb">Mehdi Mulani</a> submitted a couple patches early on and others have stepped up and are working on patches right now.</p>
<h2>My Experience So Far</h2>
<p>Honestly, this is the first large scale C/C++ project I&rsquo;ve worked on. I took &frac12; a semester of C my freshman year in college (over 6 years ago) and I&rsquo;ve written some random pieces of C++ at Mozilla. Mostly though, I write JavaScript and before that Ruby &amp; PHP - a lot of scripting languages. It&rsquo;s a drastic change from what I&rsquo;m used to and it&rsquo;s taken me a while to get comfortable. Luckily I&rsquo;m working with friends who have helped teach me as I go. Learning C++ while making one JavaScript engine work on top of another has been a real sink or swim experience.</p>
<p>It&rsquo;s been fun though. I really needed something entirely different from Firefox for a little while and this has fit the bill perfectly.</p>
<p>Expect to see more from me and others in the coming days &amp; weeks. And hey, perhaps you&rsquo;ll see one of us at NodeConf.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/Tyk3HiLRosg" height="1" width="1" alt=""/>reCAPTCHA and Gibberish2011-04-12T00:00:00-07:00https://zpao.com/posts/recaptcha-and-gibberish<p><img src="/img/posts/recaptcha-gibberish.jpg" alt=""></p>
<p>It appears the reCAPTCHA has officially gone through all of the English words and has moved on to Gibberish. For the record &ldquo;sdngl witatimo&rdquo; did work to prove I&rsquo;m human.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/vokYl5pAz-c" height="1" width="1" alt=""/>ShoeVox: Voice Control for Your PC Multimedia2011-03-10T00:00:00-08:00https://zpao.com/posts/shoevox-voice-control-for-your-pc-multimedia<p><a href="http://rsbaskin.com">Rob</a> and <a href="http://www.maxcutler.com/">Max</a> are both really smart guys who work really well together (once upon a time, the 3 of us <a href="/posts/the-rise-fall-of-courant-news">were working on a startup</a>), so I&rsquo;m excited to see that they&rsquo;ve made something cool. I don&rsquo;t fit the target audience with my OS X loving ways, but I hope others can make use of it.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/tsfYXTuvtYc" height="1" width="1" alt=""/>Multiple Assignment in JS With Objects2011-02-25T00:00:00-08:00https://zpao.com/posts/multiple-assignment-in-js-with-objects<p>Note: Turns out this only works in Firefox since it is the only browser to include versions of JavaScript beyond 1.5. Perhaps something will show up in ECMAScript N/Harmony/whatever.</p>
<hr>
<p>Alright, JavaScript is pretty cool. There are plenty of &ldquo;tricks&rdquo; that still boggle my mind. I just found another cool trick in <a href="https://github.com/Mardak/restartless/blob/examples%2Fl10nDialogs/bootstrap.js#L37">Mardak code</a> (he would do this&hellip;).</p>
<p>This is about multiple assignment in JS. Well, it&rsquo;s actually about destructuring assignment, but potato, potato.</p>
<p>Hopefully by now we all know that it can be done with arrays.</p>
<script src="https://gist.github.com/844787.js?file=assignment_array.js"></script>
<p>What I didn&rsquo;t know is that it can also be done using objects.</p>
<script src="https://gist.github.com/844787.js?file=assignment_object.js"></script>
<p>This mostly makes sense now that I know it works, I was just a bit surprised. The syntax is strange, but it&rsquo;s oddly satisfying (and follows from the assignment from an array).</p>
<p>Turns out this works for nested objects too&hellip;</p>
<script src="https://gist.github.com/844787.js?file=assignment_object_nested.js"></script>
<p>Just keep in mind the same rules for object references applies. If I change <code class="prettyprint">obj2.foo.dude</code>, that changes <code class="prettyprint">e.dude</code></p>
<p>And last but not least, we can also access values directly with nested objects.</p>
<script src="https://gist.github.com/844787.js?file=assignment_object_nested2.js"></script>
<p>Modifying <code class="prettyprint">obj2.foo.dude</code> here will have no effect on <code class="prettyprint">g</code>.</p>
<p>Add this to the list of cool things that have been implemented in JS <a href="https://developer.mozilla.org/en/JavaScript/New_in_JavaScript/1.6">1.6</a>, <a href="https://developer.mozilla.org/en/JavaScript/New_in_JavaScript/1.7">1.7</a>, and <a href="https://developer.mozilla.org/en/JavaScript/New_in_JavaScript/1.8">1.8</a>, but yet still aren&rsquo;t available in all browsers (sigh). Generators, Iterators, array comprehensions, block scoping with <code class="prettyprint">let</code>&hellip; all cool things that are used regularly within the Firefox codebase.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/I_B29Jidc2s" height="1" width="1" alt=""/>2 Years at Mozilla2011-02-23T00:00:00-08:00https://zpao.com/posts/2-years-at-mozilla<p>On February 23rd, 2009 I started full-time at Mozilla. So much has happened since then, yet it still feels like it was just a couple months ago.</p>
<p>In addition to my time as an intern, I feel like I&rsquo;ve seen a lot at Mozilla. With Firefox 4 I&rsquo;ll be seeing my 4th release; 3.0 came out very shortly into my internship, followed by 3.5 soon after I started. 3.6 was my first version where I was around for the whole release, and 4 is so close I can taste it. I&rsquo;ve had 4 bosses (Connor, Beltzner, Dietrich, and Dolske). We&rsquo;re now on our 2nd CEO; I&rsquo;ve seen 1 VP Engineering leave. I&rsquo;ve met awesome people, and attended 2 summits.</p>
<p>I&rsquo;ve worked on the password manager, satchel, session restore, the Jetpack prototype, the Add-on SDK, per tab network prioritization, and a whole bunch of random front-end stuff. I ported the Sync extension into Firefox and helped make Firefox work on Windows CE. I&rsquo;ve even written docshell &amp; widget code (even if it didn&rsquo;t all get checked in)! The fact that I&rsquo;ve gotten to work on such varying parts of Firefox is one of my favorite things about my job.</p>
<p>A lot has happened in my personal life as well. I lived by myself for the first time while Amanda was back at school (actually by myself, not counting dorm life or sharing a house). I&rsquo;ve cleaned up more cat puke than I ever thought I would. I&rsquo;ve made new friends and grown apart from older friends. <em>I got engaged!</em> I helped my fiancée start a company.</p>
<p>I guess it&rsquo;s actually been a pretty long 2 years.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/L3G8potagj4" height="1" width="1" alt=""/>Updated Firefox Extension: Always Ask 2.0pre2011-02-22T00:00:00-08:00https://zpao.com/posts/updated-firefox-extension-always-ask-2.0pre<p><img src="/img/posts/always-ask-2.0pre.png" alt="" title="The dialog that Always Ask shows when it has determined Firefox will quit without prompting"></p>
<p>Around the endgame for Firefox 3.6, <a href="/posts/just-released-always-ask">I wrote an extension called Always Ask</a> to make sure I always got a prompt when quitting. I used it for a while and then forgot about it when it was no longer compatible as Firefox 3.7 (now 4) moved forward.</p>
<p>Now that we&rsquo;re at the endgame for Firefox 4, and especially with all the changes surrounding the quit dialog, I figured it should be updated. So I&rsquo;m releasing v2.0pre today which updates the extension to work with component registration changes and <a href="/posts/just-quit-it">quit dialog</a> <a href="/posts/about-that-quit-dialog">changes</a> in Firefox 4. This also includes the translations that were submitted via Babelzilla (most of them over a year ago). Thanks to all of you who took the time to translate those strings.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/always-ask/">Get it now</a></strong>. Or <a href="https://github.com/zpao/alwaysAsk">look at the code</a>.</p>
<h2>Why 2.0 &ldquo;pre&rdquo;?</h2>
<p>Mostly just in case there are any further changes needed to be compatible with Firefox 4 (there better not be though).</p>
<h2>Why not restartless?</h2>
<p>This would probably work really well as a restartless extension. But I was really lazy and didn&rsquo;t feel like figuring out the l10n part of that (though it looks like <a href="http://erikvold.com/blog/index.cfm/2011/2/18/restartless-firefox-addons-part-4-localization-l10n">Erik Vold has that figured out already</a>).</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/QNGo1RZhp7k" height="1" width="1" alt=""/>New Firefox Extension: switch-to-tab Blacklist2011-02-18T00:00:00-08:00https://zpao.com/posts/new-firefox-extension-switch-to-tab-blacklist<p>Switch To Tab is a pretty cool feature that will be a part of Firefox 4. I didn&rsquo;t work much on it, but I contributed a bit to it last year (see <a href="/posts/switch-to-tab-closing-empty-tabs">this post</a> for one example).</p>
<p>For the most part, I really like this new feature. It&rsquo;s saved me much tab duplication over the past several month. However there are some sites that it doesn&rsquo;t play well with, namely some JavaScript &ldquo;applications&rdquo; and pages with frames. I&rsquo;ve quietly dealt with it and worked around the issues.</p>
<p>But a couple weeks ago after trying to do multiple Google Maps search, I decided that I&rsquo;d had enough. I never wanted Google Maps to show up in switch to tab and I was going to write an add-on to make that possible. So I spent a bit of time figuring out how I might do that and looking at this new bootstrapped extension stuff (which is pretty awesome by the way). I didn&rsquo;t get far enough to make it actually work and stalled. Then I got back to work and fixed some more blockers and promptly forgot about this idea.</p>
<p>Yesterday I started working on it again but my current approach wasn&rsquo;t working (turns out <code class="prettyprint">gBrowser._placesAutocomplete</code> is readonly and it means it). So I asked <a href="http://shawnwilsher.com/">Shawn</a> about it and he came up with the answer: cheat. Don&rsquo;t try to intercept the additions to the database, just revert them after the fact. Smart guy.</p>
<p>I wrote a quick and dirty version and iterated. I released a &ldquo;good enough&rdquo; version 1.0 last night. &ldquo;Good enough&rdquo; meant it was restartless but required restarting to re-process the blacklist preference, which was&hellip; dumb. Over lunch today I finished v1.1 to fix that and a couple other small issues.</p>
<h2>Let me have it</h2>
<p><a href="https://addons.mozilla.org/firefox/addon/switch-to-tab-blacklist/">switch-to-tab Blacklist on AMO</a></p>
<h2>Can I see the code?</h2>
<p><a href="https://github.com/zpao/switchToTabBlacklist">It&rsquo;s on github</a>. I need to clean it up because it&rsquo;s a bit hard to look at, so don&rsquo;t judge me too much.</p>
<h2>This picture is not worth 1000 words</h2>
<p>Previously, that autocomplete result would have been said &ldquo;Switch to tab:&rdquo;.
<img src="/img/posts/switch-to-tab-blacklist.png" alt=""></p>
<h2>Customizing the blacklist</h2>
<p>I&rsquo;m storing a JSON array of regular expressions (stored as strings which get turned into regular expressions with <code class="prettyprint">new RegExp(...)</code>). This is stored in a preference: <code class="prettyprint">extension.switchToTabBlacklist.blacklist</code>. You need to edit it by hand for now.</p>
<h2>Where&rsquo;s my GUI</h2>
<p>I don&rsquo;t have visual basic on this computer so I couldn&rsquo;t make one.</p>
<p>To be honest, I just didn&rsquo;t care enough to make it. I made this extension for me and I know how to edit a preference. I would gladly take patches though if somebody wants to make one.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/E9gE8WlcYKQ" height="1" width="1" alt=""/>About That Quit Dialog&hellip;2011-02-07T00:00:00-08:00https://zpao.com/posts/about-that-quit-dialog<p>Remember when we <a href="/posts/just-quit-it">turned it off a couple weeks ago</a>? We did that by just flipping the <code class="prettyprint">browser.warnOnQuit</code> preference to <code class="prettyprint">false</code>. I mentioned that you could get old behavior back by flipping that preference back to <code class="prettyprint">true</code>. That&rsquo;s not going to work anymore.</p>
<p>I just landed <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=629485">bug 629485</a> to change things again, so pay attention. When we turned off the quit dialog, we took away any way of stopping the last window from closing without any warning, even if you explicitly set the visible pref <code class="prettyprint">browser.tabs.warnOnClose</code> which would show the window closing warning (when you have multiple tabs). That wasn&rsquo;t so cool. So we played around with the logic and made that possible. But in order to do so, we had to change the default value of <code class="prettyprint">browser.warnOnQuit</code> to <code class="prettyprint">true</code> and create a new preference which controls the quit dialog (<code class="prettyprint">browser.showQuitDialog</code>). I know this sounds a bit inane, but there really wasn&rsquo;t a better way to do it and maintain <code class="prettyprint">browser.warnOnQuit == false</code> as an override.</p>
<p>It&rsquo;s all a bit confusing, so I&rsquo;ve <a href="http://hg.mozilla.org/mozilla-central/file/84921e24be9c/browser/components/nsBrowserGlue.js#l443">documented the conditions</a> under which we won&rsquo;t show a dialog, as well as the rules for choosing which dialog to show. Some of that comment is perfectly clear; the rest requires a little bit of understanding of the code (but it shouldn&rsquo;t be too hard to figure out if you want).</p>
<p>Don&rsquo;t expect me to write another post like this. I don&rsquo;t expect any further changes to how this stuff works.</p>
<h2>TL;DR</h2>
<ul>
<li>We enabled the window closing dialog when closing the last window would otherwise just quit (mostly important to Windows and Linux users).</li>
<li>If you want the quit dialog back, set <code class="prettyprint">browser.showQuitWarning</code> to <code class="prettyprint">true</code> and make sure <code class="prettyprint">browser.warnOnQuit</code> is also <code class="prettyprint">true</code>.</li>
</ul>
<hr>
<p><strong>Update: Feb. 8, 2011:</strong> Yup. I fucked that up a little bit. We aren&rsquo;t showing the quit dialog if you close the last window, even with the prefs mentioned above. That should be fixed in the next nightly.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/VeyAG54_Ezw" height="1" width="1" alt=""/>The New Firefox Default Home Page is Seriously Sexy2011-01-31T00:00:00-08:00https://zpao.com/posts/the-new-firefox-default-home-page-is-seriously-sexy<p><a href="/img/posts/originals/new-firefox-default-home-page.png"><img src="/img/posts/new-firefox-default-home-page.png" alt=""></a></p>
<p>The new Firefox default home page is seriously sexy. <strong>Seriously.</strong></p>
<p>A couple weeks ago <a href="http://www.stephenhorlander.com/">Stephen Horlander</a> designed an updated default home page for Firefox. Over the weekend, we landed most of it. So first off, a huge thanks to him.</p>
<p>Mihai Sucan did an awesome job converting the HTML &amp; CSS Steven prototyped into something we could check in, which involved a lot of fun with media queries (seriously, resize your window with it open), as well as a lot of work to make sure it worked with RTL locales.</p>
<p>And then finally, I hooked up the &ldquo;Restore Previous Session&rdquo; button. Not the HTML &amp; CSS (that was Stephen &amp; Mihai), just the parts that made it hide when appropriate and work when pressed. Now hopefully a few people realize that feature exists :)</p>
<p>I also can&rsquo;t forget to mention <a href="http://blog.bonardo.net/">Marco Bonardo</a>, who hooked up <code class="prettyprint">about:home</code> back in August so that we could even get to this point.</p>
<p>Keep in mind, the image I&rsquo;m showing here is the unbranded &ldquo;Minefield&rdquo; version of the page. When loading this in Firefox it won&rsquo;t look like your computer is going to explode. I think there is a little bit more tweaking that will be done, but it already looks so much better than it used to.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/GcZKLwGeJPg" height="1" width="1" alt=""/>The California DMV has Terrible Browser Recommendations2011-01-31T00:00:00-08:00https://zpao.com/posts/the-california-dmv-has-terrible-browser-recommendations<p>It appears as though the California DMV has not updated their website in the past 10 years&hellip;</p>
<blockquote>
<p>To be able to use this online application, your computer will need to have one of the latest versions of either the Internet Explorer, Netscape Communicator/Navigator, or equivalent web browsers. For Internet Explorer you must have version 4.0 or higher. We suggest you use Netscape Communicator/Navigator version 6.0 or higher to eliminate any possible printer problems.</p>
</blockquote>
<p>&ndash; <a href="https://www.dmv.ca.gov/online/dlrbi/faqbrowser.htm">California DMV Browser Requirements</a></p>
<p>Internet Explorer 4 came out in 1997. Netscape 6 came out in 2000. How far we&rsquo;ve come&hellip;</p>
<p>In related news, the next available appointment (to take the &ldquo;written&rdquo; test) at the DMV in San Francisco is halfway through March. I bet I could get a new passport sooner.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/rNHSYCuTJCg" height="1" width="1" alt=""/>Just Quit It2011-01-21T00:00:00-08:00https://zpao.com/posts/just-quit-it<p>For a long time now, if you didn&rsquo;t have Firefox set to restore your session then Firefox would prompt you before quitting. A dialog with 3 buttons and a checkbox. It looked like this:</p>
<p><img src="/img/posts/just-quit-it.png" alt=""></p>
<p>That mostly just gets in your way though. You&rsquo;ve already decided you want to quit. You don&rsquo;t also need to decide if you want to reopen your tabs next time. So starting with the next nightly (January 21st) and Firefox 4 beta 10, you will no longer see that prompt. Of course if you already checked the box to &ldquo;not ask next time&rdquo; you weren&rsquo;t seeing this anyway.</p>
<p>Essentially, all we did was flip a preference that has been there since Firefox 3 (that was almost 3 years ago for those of you keeping track at home). <code class="prettyprint">browser.warnOnQuit</code> was added as hidden preference to override other conditions that might cause a dialog shown at quit. We set that to <code class="prettyprint">false</code>. <strike>If you want Firefox 3.* behavior, then just flip the pref back to <code class="prettyprint">true</code>.</strike></p>
<p>If you&rsquo;re interested, this was done in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=592822">bug 592822</a> (it was originally planned as part of <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=588482">bug 588482</a>).</p>
<h2>Dude, Where&rsquo;s My Session?</h2>
<p>I know it&rsquo;s been a while since <a href="/posts/restore-previous-session">I wrote about it</a>, but it&rsquo;s now possible to restore your session on demand after startup. There is work underway to make that feature more visible, namely <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=593421">bug 593421</a> (to add a button on the start page) and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=589665">bug 589665</a> (to add a button in Panorama).</p>
<hr>
<p><strong>Update (Feb. 7, 2011):</strong> We had to make some further changes. We kept the dialog turned off by default but had to do some work with preferences. Setting <code class="prettyprint">browser.warnOnQuit</code> is no longer good enough to show the quit dialog. <a href="/posts/about-that-quit-dialog">Read more</a></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/77MCEzDA09s" height="1" width="1" alt=""/>Radiohead: 01 and 102011-01-15T00:00:00-08:00https://zpao.com/posts/radiohead-01-and-10<p>This might be old news to some, but I found it pretty interesting&hellip;</p>
<blockquote>
<p>Consider that In Rainbows was meant to complement OK Computer, musically, lyrically, and in structure. We found that the two albums can be knit together beautifully. By combining the tracks to form one playlist, 01 and 10, we have a remarkable listening experience. The transitions between the songs are astounding, and it appears that this was done purposefully.</p>
</blockquote>
<p>I set this playlist up and it really is a great listening experience. It might not be intentional but I don&rsquo;t care. If you have both albums give it a listen.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/6d8JTNygRCM" height="1" width="1" alt=""/>Use a Pager with Mercurial2011-01-14T00:00:00-08:00https://zpao.com/posts/use-a-pager-with-mercurial<p>In the spirit of sharing Mercurial extensions this week, did you know that there&rsquo;s a <a href="http://mercurial.selenic.com/wiki/PagerExtension">pager extension</a> that ships with Mercurial? After using Git for a while and having a nice pager when looking at diffs, I got really annoyed by the fact that I constantly had to scroll my terminal for <code class="prettyprint">hg diff</code>. I found the Pager extension and there was much rejoicing.</p>
<p>So turn it on and be happy. It&rsquo;ll only page when you need to. And while you&rsquo;re in your <code class="prettyprint">.hgrc</code>, enable the also-shipped-but-not-on-by-default <a href="http://mercurial.selenic.com/wiki/ColorExtension">Color extension</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/Jb9VyswXkKo" height="1" width="1" alt=""/>hg-prompt Makes My Eyes Happier2011-01-10T00:00:00-08:00https://zpao.com/posts/hg-prompt-makes-my-eyes-happier<p>For a long time I&rsquo;ve had Git info in my terminal prompt. At Mozilla, we mostly use Mercurial though, so a Git aware terminal wasn&rsquo;t super helpful. A couple times I tried to hack together something for Mercurial to show me my current branch or applied patch queue. Every time though I either didn&rsquo;t get everything I wanted or was too lazy to make it work like I wanted (and play nicely with my other customizations).</p>
<p>This morning I started on this problem again. But this time I started by searching for a solution first and voilà, I found hg-prompt. Take a look at <a href="http://sjl.bitbucket.org/hg-prompt/documentation/samples/">the samples</a> and then customize it with the <a href="http://sjl.bitbucket.org/hg-prompt/documentation/keywords/">extended list of keywords available</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/DtZzvNSQN5A" height="1" width="1" alt=""/>Pagination: Next, Next, Previous2010-12-22T00:00:00-08:00https://zpao.com/posts/pagination-next-next-previous<p>Nobody has said anything but I haven&rsquo;t had pagination enabled on this blog since it started. It was initially cut from the theme since I didn&rsquo;t like what I&rsquo;d done and I didn&rsquo;t have to worry about it.</p>
<p>This summer I realized I had more than 1 page of content but didn&rsquo;t care enough.</p>
<p>Tonight I just took out the comments that had been hiding the content. Turns out what I had designed is good enough to get the point across.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/JJe6YQrxrJk" height="1" width="1" alt=""/>Through the Spam Filter2010-11-23T00:00:00-08:00https://zpao.com/posts/through-the-spam-filter<blockquote>
<p>Hi dear,
you are very nice
I wish i could get to know you for
it is my pleasure to have you as my friend
for a friend is all about Respect,,,Admiration,contentious and
affectionante also friendship is consist of sharing of ideas and
showing true affection without cheats,,,lies and betray so can you
welcome me, lets get to the ocean of love ?????????????
I am miss lucy by name</p>
</blockquote>
<p>Certainly not the most interesting piece of email to ever make it through the spam filter, but seriously, <strong>LET&rsquo;S GET TO THE OCEAN OF LOVE ?????????????</strong></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/gpO9BYxh8Pk" height="1" width="1" alt=""/>Amazon and HTML52010-11-10T00:00:00-08:00https://zpao.com/posts/amazon-and-html5<p><a href="/img/posts/originals/amazon-and-html5.png"><img src="/img/posts/amazon-and-html5.png" alt=""></a></p>
<p>Apparently Amazon is stepping right into HTML5 and using <code class="prettyprint">type=&quot;email&quot;</code> in their sign in form. You can see the built-in form validation in action there. This is pretty awesome to actually see out in the wild, especially from such a big name.</p>
<p>Client-side form validation without various JS libraries is pretty cool. <a href="http://blog.oldworld.fr/index.php?post/2010/11/17/HTML5-Forms-Validation-in-Firefox-4">Read more about it</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/bcl0jvTQUIA" height="1" width="1" alt=""/>Reset Panorama from the Error Console.2010-10-21T00:00:00-07:00https://zpao.com/posts/reset-panorama-from-the-error-console<p><a href="http://www.azarask.in/blog/post/designing-tab-candy/">Panorama</a> is this cool new feature coming to Firefox 4. Most of the big issues have been fixed, but there&rsquo;s still <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=598600">the occasional issue</a> with orphan tabs.</p>
<p>Last week I wrote <a href="https://gist.github.com/626761">a script</a> that would strip the Panorama data out of Session Restore. That worked but would require a restart. <a href="http://www.iangilman.com/">Ian Gilman</a> (one of the Panorama developers) used that script for the basis of <a href="https://gist.github.com/637583">a script</a> that worked much better (it actually called into Panorama and told it to reset properly). The only problem is that it left tabs hidden, so it would require jumping into and then out of TabView to bring everything back to normal. I forked that and just added a call that made sure all tabs were shown.</p>
<p>So if you ever get into a confusing state and don&rsquo;t mind wiping out your current Panorama data, this script is for you:
<script src="https://gist.github.com/638855.js"> </script></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/COlb3lebzsc" height="1" width="1" alt=""/>P-I-Z-Z-A I want pizza!2010-10-17T00:00:00-07:00https://zpao.com/posts/p-i-z-z-a-i-want-pizza<iframe width="640" height="480" src="http://www.youtube.com/embed/wusGIl3v044?rel=0" frameborder="0" allowfullscreen></iframe>
<blockquote>
<p>P-I-Z-Z-A I want pizza!</p>
</blockquote>
<img src="http://feeds.feedburner.com/~r/zpao/~4/VphhW2rmG4Y" height="1" width="1" alt=""/>The Clipper Card System is a Fucking Mess2010-10-11T00:00:00-07:00https://zpao.com/posts/the-clipper-card-system-is-a-fucking-mess<p>Here&rsquo;s (only part of) why:</p>
<blockquote>
<p>Please note that when you add value online, it can take up to 3 days for the value to be available to be loaded onto your card, and you must tag your card to a card reader to load the value. Your card balance will not be updated until you have tagged your card and loaded the value.</p>
</blockquote>
<p>3 days? By then I&rsquo;ll have needed it 3 days ago.</p>
<p>Another gem:</p>
<blockquote>
<p>Cable car operators will be equipped with hand held card readers which can verify that a current Monthly Pass exists on your Clipper card. The card readers cannot deduct a cash fare, so customers paying with cash or 10-ride books are not yet able to ride the cable cars using Clipper.</p>
</blockquote>
<p>I&rsquo;ve seen failures on Muni where the stupid reader doesn&rsquo;t work. No cash? Sorry get off the bus. On Caltrain I&rsquo;ve seen people with autoload not have their card autoloaded. Operators tend to be understanding (&ldquo;Oh yea these things kinda suck&rdquo;), but the current condition is not great.</p>
<p>I realize that this is one step towards the cashless future we see in movies. I just wish it wasn&rsquo;t going to be a clusterfuck getting there.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/-BJ3ruvEM-E" height="1" width="1" alt=""/>&lt;3 Firefox Sync2010-09-24T00:00:00-07:00https://zpao.com/posts/firefox-sync<p>Today I accidentally deleted my primary Firefox profile (mostly through user error). I was cleaning testing profiles out via the <a href="http://support.mozilla.com/kb/managing+profiles">Profile Manager</a> and managed to delete <code class="prettyprint">default</code>. Since that actually deletes the whole profile folder from disk instead of moving to the trash can, I just said &ldquo;Fuck&rdquo;. This is a profile I&rsquo;ve had for a while. It had a lot of history, passwords, bookmarks, extensions. All of it lost in an instant.</p>
<p>Luckily though, I&rsquo;d set this profile up to use Firefox Sync years ago when early versions of Weave were just being released. At that point I&rsquo;d set it up for backup primarily. Since then I&rsquo;ve synced that profile to multiple computers.</p>
<p>The nice thing about it is I lost almost 0 time. I created a new profile, set up Sync, and within a couple minutes had the vital information I needed in my profile. I lost a couple things: extensions, some prefs. I don&rsquo;t use many extensions so that&rsquo;s not a huge issue. I don&rsquo;t even remember what prefs I&rsquo;ve tweaked, but I&rsquo;m going to guess not too many. Some prefs were restored by Sync, but there&rsquo;s only a handful that get synced. I even had all of my tabs a click away on the list of tabs from other computers.</p>
<p>If you&rsquo;re not using Firefox Sync, <a href="http://www.mozilla.com/en-US/firefox/beta/features/">it&rsquo;s built in to Firefox 4</a> and is also <a href="https://addons.mozilla.org/en-US/firefox/addon/10868/">available as an extension</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/cEO27dnYxsQ" height="1" width="1" alt=""/>I Don&rsquo;t Blog Here Anymore2010-09-22T00:00:00-07:00https://zpao.com/posts/i-dont-blog-here-anymore<p>My homegrown blogging engine worked for a while, but I just don&rsquo;t have the time to make the changes I want. Not only that, but when I blog here, I feel like I need to put a lot of thought into each article. That&rsquo;s not something I have the time to do for everything I want to share.</p>
<p>Several months ago, I decided to give <a href="http://tumblr.com">Tumblr</a> another shot. So far it&rsquo;s been working out. It gives me a little bit more flexibility. I can write a thoughtful article, or I can share a funny video I found on YouTube. I feel a lot less pressure to make every post super meaningful.</p>
<p>Eventually I&rsquo;ll put on a fresh coat of paint here and make this more of a launching point to my separate content. I&rsquo;ll still keep the articles around accessible by their current URLs regardless of what I do.</p>
<p>If you&rsquo;re an RSS kind of person &amp; you subscribed to the Feedburner feed, you&rsquo;ll automagically get switched over to the new feed soon.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/fmijqEhzr24" height="1" width="1" alt=""/>I Already Love It2010-09-21T00:00:00-07:00https://zpao.com/posts/i-already-love-it<blockquote>
<p>I already love it. I had to wait several minutes til my 100+ tabs are loaded. Now i can start to surf immediately.</p>
</blockquote>
<p>—<a href="http://forums.mozillazine.org/viewtopic.php?p=9915641&amp;sid=5169dfe4ca931dad2c643f083536b945#p9915641">trolly on mozillazine</a> about <a href="/posts/cascaded-session-restore-a-hidden-bonus">Cascaded Session Restore</a></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/fxU-E-pS-Gw" height="1" width="1" alt=""/>Cascaded Session Restore + a Hidden Bonus2010-09-17T00:00:00-07:00https://zpao.com/posts/cascaded-session-restore-a-hidden-bonus<p><em>In the tradition of announcing major things on Friday nights&hellip;</em></p>
<p>I did this thing where we don&rsquo;t load all of your pages at once when we restore your session. That should keep your Firefox (and computer in general) a bit more usable when you start up Firefox with a large session. See <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=586068">bug 586068</a> if you&rsquo;re interested in the juicy details.</p>
<h2>Other Details</h2>
<ul>
<li>Switching tabs should cause the selected tab to start loading immediately, even if it wasn&rsquo;t loading before</li>
<li>This works with Panorama (so changing groups re-prioritizes your load order).</li>
</ul>
<h2>Preference Controlled</h2>
<p>We load a certain number of tabs based on the <code class="prettyprint">browser.sessionstore.max_concurrent_tabs</code> preference. We&rsquo;ve set the default to 3 for now.</p>
<h2>Hidden Bonus</h2>
<p>Set the pref to 0. It&rsquo;s basically a built-in <a href="https://addons.mozilla.org/en-US/firefox/addon/67651">BarTab</a>.</p>
<h2>Quirks</h2>
<p>We show the page title and favicon at start up, before we try to load the page. So you might see some slightly odd behavior. Panorama&rsquo;s thumbnail caching isn&rsquo;t perfect, so there will probably be missing thumbnails at start up if you switch into the Panorama view.</p>
<p>Please email me (link below!) or file a bug blocking 586068 if you see anything weird.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/8N2iOduAfFw" height="1" width="1" alt=""/>Restore Previous Session2010-09-10T00:00:00-07:00https://zpao.com/posts/restore-previous-session<p>I landed <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=588482">bug 588482</a> today (September 10<sup>th</sup>), so starting with tomorrow&rsquo;s nightly version of Firefox (AKA Minefield), you&rsquo;ll be able to restore your previous session at any point after start up. This means that you no longer have to restore your whole session immediately at start up. This will be available through a menu item in the History menu, as shown below.</p>
<p><img src="/img/posts/restore-previous-session.png" alt="Screenshot of History Menu"></p>
<p>This feature will be in Firefox 4 <strike>beta 6</strike> beta 7, due out in the next couple weeks.</p>
<h2>Details</h2>
<ul>
<li>Restoring your previous session after you&rsquo;ve browsed around will merge the sessions. You shouldn&rsquo;t lose any new data by restoring your previous session.</li>
<li>We didn&rsquo;t break existing behavior. If you have Firefox set to show your windows and tabs from last time, we&rsquo;ll continue to do so and you won&rsquo;t even notice this feature exists</li>
<li>App tabs still behave the same.</li>
<li>This doesn&rsquo;t break any existing APIs, but it does add some new ones.</li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=593421">Discoverability is suboptimal</a>.</li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=592822">You are still prompted to save your session when quitting</a> (assuming default prefs).</li>
</ul>
<h2>Why?</h2>
<p>We did this primarily for 2 reasons.</p>
<ol>
<li>We want faster start up times. By encouraging users to always resume their previous sessions, we give the impression that Firefox takes a long time to load up. But really, you&rsquo;re loading 20, 50, 100+ tabs and that&rsquo;s what is slow.</li>
<li>When you&rsquo;re quitting, you there&rsquo;s a good chance you have no idea if you&rsquo;ll need your tabs next time.</li>
</ol>
<p>(Keep in mind, if you&rsquo;re reading this post, you aren&rsquo;t the typical user. You&rsquo;re probably a developer of some sort who drags your 400 tabs around to each session. You know it&rsquo;s slow, but you really never got the hang of bookmarks, so you just keep tabs open.)</p>
<h2>Privacy</h2>
<p>Obviously, in order for us to restore your session, we need to save it to disk. We save this data in a plain-text JSON file in your <a href="http://support.mozilla.com/kb/Profiles">profile</a>.</p>
<p>We currently consider sessions a little differently than some other browsers. We consider your session cookies (and a few other things) as part of your session. This means we write that information to disk. Under a normal session restore that you&rsquo;ve explicitly opted-in to, that&rsquo;s fine. We have a hidden preference (<code class="prettyprint">browser.sessionstore.privacy_level</code>) that specifies what level of privacy to use. <strong>The default value is 1</strong>.</p>
<p>There are 3 levels of privacy:</p>
<ul>
<li><strong>0</strong> = Save private information for HTTP and HTTPS sites.</li>
<li><strong>1</strong> = Save private information for HTTP sites.</li>
<li><strong>2</strong> = Don&rsquo;t save any private information.</li>
</ul>
<p>For deferred sessions, we created a new preference (<code class="prettyprint">browser.sessionstore.privacy_level_deferred</code>) with a different default value. Since people are not making an informed decision to restore at shutdown, we don&rsquo;t want to expose information that can be used to, for example, log in to GMail. This new preference has the same possible values but <strong>the default value is 2</strong>, so that no session cookies will be restored.</p>
<h2>Safari</h2>
<p>Yea. They&rsquo;ve been doing this for ages. But as far as I know, they still don&rsquo;t allow you to restore your entire session at start up.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/clbtn84Cj4I" height="1" width="1" alt=""/>Helo, i&rsquo;m a noob2010-08-17T00:00:00-07:00https://zpao.com/posts/helo-im-a-noob<blockquote>
<p>Helo - i&rsquo;m a noob; pls be kind. i&rsquo;m using getelementbyID to submit a form to a script, and want to prevent injection attacks. Is there a custom php function you&rsquo;d reccomend, or is there a way to post an element instead of get?</p>
</blockquote>
<p>—ragas (on <a href="irc://irc.freenode.net/#javascript">##javascript on freenode</a>)</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/R3Gl-AQdPUw" height="1" width="1" alt=""/>Jetpack SDK 0.5 &amp; the Request API2010-06-29T00:00:00-07:00https://zpao.com/posts/jetpack-sdk-0-5-the-request-api<p><a href="http://mozillalabs.com/jetpack/2010/06/24/announcing-jetpack-sdk-0-5/">Jetpack SDK 0.5</a> hit the streets last week. There&rsquo;s a bunch of new APIs in there. I worked on the <code class="prettyprint">Request</code> API, which enables a simple way to make XML HTTP Requests (XHR, or AJAX if you must). The API is a wrapper around the Gecko HXR object.</p>
<p>Like jQuery, MooTools, Prototype (or pretty much any JS library), it makes the ugly stuff go away. You simple provide a URL, some data, and a callback, and we&rsquo;ll do the rest (you can set some more things if you&rsquo;d like). In the callback, you have access to the response headers and content as JSON/XML/text. <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/request">Read the documentation</a> for the specifics.</p>
<p>Keep in mind that this is meant to be a simple API. You can&rsquo;t make complicated requests. For example, you can&rsquo;t send files with it. The plan is to keep this API simple. It is a first version, so if people need more functionality, we can add more. Or we can take those additional needs and create another API. If you have feedback, please post to the <a href="https://groups.google.com/group/mozilla-labs-jetpack">Google Group</a>.</p>
<p>I wrote up a basic example using the Twitter API, which I&rsquo;ve included below. It&rsquo;s not too fancy, but gets your feet wet.</p>
<script src="https://gist.github.com/457704.js?file=gistfile1.js"></script>
<img src="http://feeds.feedburner.com/~r/zpao/~4/277RU4VrAfo" height="1" width="1" alt=""/>The Good Life in Concert2010-06-17T00:00:00-07:00https://zpao.com/posts/the-good-life-in-concert<iframe width="640" height="360" src="http://www.youtube.com/embed/mu0SqIGE338?rel=0" frameborder="0" allowfullscreen></iframe>
<p>Last Thursday I saw <a href="http://www.thegoodlifemusic.com">The Good Life</a> play at <a href="http://www.bottomofthehill.com">Bottom of the Hill</a> with Victoria and Megan. With the exception of the obnoxiously loud drunk girl dropping pint glasses nearby, it was one of the better shows I&rsquo;ve been to in a while. Tim Kasher is just a great performer and he really pours his heart into the music. Bottom of the Hill is a small venue, but for a band like The Good Life, the intimacy is entirely appropriate. They played a lot of fan favorites and even covered Fleetwood Mac&rsquo;s &ldquo;The Chain,&rdquo; which was pretty cool. They finished strong with &ldquo;Album of the Year&rdquo; as seen in the video above.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/JOc8C6Cw9Bw" height="1" width="1" alt=""/>Switch to Tab &amp; Closing Empty Tabs2010-06-15T00:00:00-07:00https://zpao.com/posts/switch-to-tab-closing-empty-tabs<p>Firefox 4 will be introducing a <a href="https://wiki.mozilla.org/Firefox/Projects/Tab_Matches_in_Awesomebar">new feature</a> called &ldquo;Switch to Tab&rdquo; or &ldquo;Tab Matches in Awesomebar&rdquo;, a feature that attempts to see if the page you&rsquo;re looking for is already open. If it is (and you explicitly select that location bar suggestion), you&rsquo;ll be taken to that open tab instead of opening a new one. This is great step forward &amp; I&rsquo;ve already found it quite helpful. I tend to open the same bug several times over the course of a day or week. Now instead of having 3 copies, I can just have one and switch to it quickly.</p>
<p>Even though <a href="http://theunfocused.net">Blair</a> toiled away on it, there were still a few bugs with the initial implementation. Blair immediately jumped into another small project (redesigning the Add-ons Manager is pretty trivial right?), so many of the followup bugs went unowned. I took two of those bugs; I fixed <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=556061">one</a> a few weeks ago and finally fixed the <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=555767">other</a> today.</p>
<p>The second one is the one that will make more of a difference for user experience. My common workflow goes like this (notice the brokenness at the end):</p>
<ol>
<li>Open a new tab</li>
<li>Start typing new URL</li>
<li>Sweet, a match! Switch to it.</li>
<li>Repeat 1-3</li>
<li>WTF? I have 15 blank tabs open?</li>
</ol>
<p>With <a href="http://hg.mozilla.org/mozilla-central/rev/2333f6d349d7">my patch</a> <em>we&rsquo;ll now close that empty tab after we switch focus</em>. No more step 5. That is all.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/A85tdLAL3ck" height="1" width="1" alt=""/>I&rsquo;m Comic Sans, Asshole.2010-06-15T00:00:00-07:00https://zpao.com/posts/im-comic-sans-asshole<blockquote>
<p>People love me. Why? Because I&rsquo;m fun. I&rsquo;m the life of the party. I bring levity to any situation. Need to soften the blow of a harsh message about restroom etiquette? SLAM. There I am. Need to spice up the directions to your graduation party? WHAM. There again. Need to convey your fun-loving, approachable nature on your business&rsquo; website? SMACK. Like daffodils in motherfucking spring.</p>
</blockquote>
<p>(via <a href="http://twitter.com/johnolilly">@johnolilly</a>)</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/kFPqC0tVhm0" height="1" width="1" alt=""/>Are Cameras the New Guns?2010-06-11T00:00:00-07:00https://zpao.com/posts/are-cameras-the-new-guns<blockquote>
<p>Almost without exception, police officials have staunchly supported the arresting officers. This argues strongly against the idea that some rogue officers are overreacting or that a few cops have something to hide. &ldquo;Arrest those who record the police&rdquo; appears to be official policy, and it&rsquo;s backed by the courts.</p>
</blockquote>
<p>I&rsquo;ve take a <a href="http://www.flickr.com/photos/zpao/sets/72157613241445785/">few photos</a> of officers in action without arrest. I&rsquo;m worried by the direction the law is heading &ndash; that it becomes a crime punishable by multiple years in prison, just for photographing a cop (doing something wrong).</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/MBHifjgQvl0" height="1" width="1" alt=""/>Now Using JSON.parse in Session Restore2010-06-09T00:00:00-07:00https://zpao.com/posts/now-using-json-parse-in-session-restore<p>Back in March, <a href="/posts/partially-dropping-support-for-firefox-2-0-3-0">I partially dropped support for sessions from Firefox 2.0 &amp; 3.0</a>. For Firefox 4.0, we&rsquo;ll be dropping backwards compatibility of sessions for Firefox 2.0 &amp; 3.0. That means that sessions created with nightlies starting tomorrow, will no longer be loadable by versions of Firefox prior to 3.5. With <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=387859">bug 387859</a>, Session Restore will now use <code class="prettyprint">JSON.parse</code> instead of <code class="prettyprint">evalInSandbox</code>.</p>
<h2>So why use <code class="prettyprint">JSON.parse</code>?</h2>
<p>Mostly, it&rsquo;s faster. <code class="prettyprint">evalInSandbox</code> involved going through XPConnect and a whole bunch of object wrapping for security needed to be done. By using <code class="prettyprint">JSON.parse</code>, we don&rsquo;t have to worry about that overhead. We also don&rsquo;t have to worry about changes made to Chrome Object Wrappers (changes which have broken about:sessionrestore recently).</p>
<h2>What does this mean for me? Not Much.</h2>
<ul>
<li>If for some reason you&rsquo;re bouncing between nightlies and Firefox 3.0, then you&rsquo;ll want to load your session in Firefox 3.5 or 3.6 before loading it in Firefox 3.0 again. If this describes you, then you should really <a href="http://www.mozilla.com/firefox/firefox.html">just upgrade</a>.</li>
<li>The contents of <code class="prettyprint">sessionstore.js</code> will no longer have wrapping parenthesis. Those were added so that sessions could still be loaded by Firefox 3.0-.</li>
<li>The keys that were only ever used internally are now excluded from exported sessions. This includes <code class="prettyprint">_tabStillLoading</code>, <code class="prettyprint">_hosts</code>, and <code class="prettyprint">_formDataSaved</code>.</li>
</ul>
<img src="http://feeds.feedburner.com/~r/zpao/~4/di3urI3MDjg" height="1" width="1" alt=""/>Special Offer2010-06-04T00:00:00-07:00https://zpao.com/posts/special-offer<p><img src="/img/posts/special-offer.gif" alt=""></p>
<p>You&rsquo;ve all seen these. They&rsquo;re all over purchase confirmation pages on sites like TicketMaster, CampusFood, Fandango. This particular one was on TicketWeb (<a href="http://www.theindependentsf.com/calendar/event-detail/?tfly_event_id=7979">after buying tickets to see Matt Pond PA</a>).</p>
<p>There&rsquo;s a lot not to understand here&hellip; I don&rsquo;t understand why these special offers are always presented as images. Nor do I understand why they would use a button from 1995. Nor do I understand why the button text is anti-aliased but the text text isn&rsquo;t.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/s_U9fG4PoaA" height="1" width="1" alt=""/>waitForClipboard now available to Mochitests2010-06-02T00:00:00-07:00https://zpao.com/posts/waitforclipboard-now-available-to-mochitests<p>Testing is a part of life. Sadly, that means we have to write tests for things that involve the clipboard. The clipboard is complicated enough with all of this flavor and transferable stuff we have going on. Throw in the fact that the clipboard can be asynchronous (thanks Linux), and it gets worse. We&rsquo;ve had a number of tests that fail due to expectations that the clipboard be synchronous. Most of those tests have been changed to use a &ldquo;polling&rdquo; strategy - essentially waiting for the clipboard to have the expected value. If it doesn&rsquo;t have the right value after a few seconds, then the test fails. I know of at least 3 tests that use this strategy now, and they all ended up having similar code, perhaps even copy-pasted directly from another test.</p>
<p><a href="http://www.gavinsharp.com/">Gavin</a> made me use polling for the test in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=556061">a bug</a> I fixed recently. Then the following week there was a password manager bug that I saw doing clipboard stuff (without polling) so I passed along the &ldquo;polling is good&rdquo; requirement.</p>
<p>Instead of making everybody rewrite the wheel, I decided to write <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=567870"><code class="prettyprint">SimpleTest.waitForClipboard</code></a> to take care of this polling stuff for us. It only works with the global clipboard, and only with <code class="prettyprint">text/unicode</code> strings (<code class="prettyprint">text/plain</code> should work too since it&rsquo;s available on the clipboard in the unicode flavor). It works by setting the clipboard to a known value (different than your expected value), then polling for that value. After the known value is found, your setup function is called, and we poll again. When we find the value, we add a <strong>PASS</strong> &amp; then your success function is called. If at any point we timeout waiting for the expected value, we add a <strong>FAIL</strong> &amp; then your failure function is called.</p>
<p>Following are the arguments and then a simple example test. Hopefully it&rsquo;s clear how to make use of <code class="prettyprint">waitForClipboard</code> in tests you write in the future. I&rsquo;ve already converted a few tests to use this method. If there are any existing [orange]s that you think could benefit from this, please convert them!</p>
<script src="https://gist.github.com/423041.js"></script>
<img src="http://feeds.feedburner.com/~r/zpao/~4/pYueBehq528" height="1" width="1" alt=""/>The Secret Diary of Steve Jobs : Guest blogger: John Gruber2010-05-26T00:00:00-07:00https://zpao.com/posts/the-secret-diary-of-steve-jobs-guest-blogger-john-gruber<p><strong>Update:</strong> Oh right, FSJ is entirely satire. I feel dumb, but I&rsquo;ll leave the original post intact. I still stand by the first paragraph.</p>
<hr>
<p>I used to like <a href="http://daringfireball.net/">John Gruber</a> a lot. I feel like he&rsquo;s gotten pretty arrogant and a tad ignorant over the past few years. He&rsquo;s written some great articles and had many insightful comments. He&rsquo;s also written some FUD. Nowadays I kind of think he&rsquo;s an ass. Keep in mind, I&rsquo;m a big Mac fan, have multiple Mac products. But I try to keep my viewpoint a bit rounded and not let myself get completely blinded by the light.</p>
<p>With this coming from FSJ, I&rsquo;m not 100% sure this is actually John Gruber, but regardless, it makes me feel even more strongly that he&rsquo;s an ass.</p>
<p>Here&rsquo;s a choice quote:</p>
<blockquote>
<p>&hellip; and OS X Snow Leopard is the top-selling operating system on Amazon for the 125th straight week, so you tell me who’s right and who’s wrong. Yeah. I thought so. You’ve just been destroyed. Crushed. Embarrassed and humiliated, ground to dust under the heel of my boot. Be gone now, you Windows loving FUD machine. You ugly Apple hating troll. You porn-loving Android user, pleasuring yourself with your Nexus One.</p>
</blockquote>
<ol>
<li>Even including pre-sales, that means Snow Leopard has been on sale for 2.5 years! I&rsquo;m calling shenanigans on that.</li>
<li>Go ahead and take a look at the <a href="http://www.amazon.com/gp/bestsellers/software/229653/ref=pd_ts_sw_nav">&ldquo;Best Sellers in Operating Systems&rdquo; page</a>. Is it just me or does that say Windows 7?</li>
</ol>
<p>So Mr. (Fake?) Gruber. <em>You</em> are wrong.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/SFfoBHzFzrU" height="1" width="1" alt=""/>The Evolution of Privacy on Facebook2010-05-07T00:00:00-07:00https://zpao.com/posts/the-evolution-of-privacy-on-facebook<p>This is by far the best visualization I&rsquo;ve seen on how Facebook&rsquo;s privacy has changed over time.</p>
<p>(via <a href="http://twitter.com/fligtar/status/13573156229">@fligtar</a>, <a href="http://twitter.com/joedrew/status/13571134468">@joedrew</a>, <a href="http://twitter.com/tieguy/status/13570338427">@tieguy</a>)</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/_1ojYgLrXNo" height="1" width="1" alt=""/>Problem Report: Cat2010-05-01T00:00:00-07:00https://zpao.com/posts/problem-report-cat<p><a href="/img/posts/originals/problem-report-cat.png"><img src="/img/posts/problem-report-cat.png" alt=""></a></p>
<p>Fact: Cats make things happen that you never expect. Like crash your computer. <a href="http://twitter.com/zpao/status/10605017612">See also</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/wWErnHxn8Nk" height="1" width="1" alt=""/>A Followup to Flash on Windows2010-04-27T00:00:00-07:00https://zpao.com/posts/a-followup-to-flash-on-windows<p>Last week I went on a <a href="/posts/how-to-install-flash-on-windows-or-a-cleveland-steamer-is-a-better-experience">little rant</a> about Adobe&rsquo;s inane method of installing Flash on Windows (in Firefox). I received a few emails from people pointing out the much better way of installing Flash - just download the .exe installer! Sounds simple, but good luck actually finding that on Adobe&rsquo;s website (while using Firefox anyway - they do UA sniffing to make you use the extension). I&rsquo;d known that this existed and this was exactly what I was expecting. I just couldn&rsquo;t find that page with minimal effort, so I thought I&rsquo;d rant.</p>
<p>I was also directed towards the <a href="http://support.mozilla.com/en-US/kb/Installing+the+Flash+plugin">Installing the Flash Plugin article</a> on the Mozilla Support website. The support moderators have dealt with the experience I had and spent a lot of time getting the support article right.</p>
<p>That article explain 2 methods of installing Flash, neither of with involves Adobe DLM:</p>
<ol>
<li>Install Flash through the missing plugin dialog. This involves simply going to <a href="http://www.adobe.com/software/flash/about/">a page that requires Flash</a> (without the usual JS fallback, ie. not YouTube) and getting prompted by Firefox to install Flash for you.</li>
<li>Installing via the .exe installer. There is a <a href="http://get.adobe.com/flashplayer/thankyou/?installer=Flash_Player_10_for_Windows_-_Other_Browsers">direct link to the page on Adobe&rsquo;s site</a> where you can download the actual installer.</li>
</ol>
<p>So there are sane ways to get Flash installed. Adobe just doesn&rsquo;t promote them.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/IRcVhplL4e4" height="1" width="1" alt=""/>How to Install Flash on Windows OR A Cleveland Steamer is a Better Experience2010-04-21T00:00:00-07:00https://zpao.com/posts/how-to-install-flash-on-windows-or-a-cleveland-steamer-is-a-better-experience<p>I got a 2nd computer at work which I&rsquo;ve installed Windows 7 onto. So I wanted to finally see the <a href="http://www.mozilla.com/en-US/firefox/3.6.4/whatsnew/#oopp">Out Of Process Plugins coming in Firefox 3.6.4</a>. It&rsquo;s a new computer, so I still need to install Flash. No problem, right? <em>Wrong!</em></p>
<p>Pretend for a moment that a helpful Adobe customer service agent is helping your mother install Flash:</p>
<ol>
<li>You need Flash! Go download it.</li>
<li>Oh and by the way, we&rsquo;re going to trick you into installing some McAffee product that you don&rsquo;t want! I mean, we&rsquo;re not tricking you, we&rsquo;re helping you&hellip;</li>
<li>Oh you&rsquo;re using Firefox? We have an <em>awesome</em> way of installing Adobe products: an extension! You know that way you normally install things on a Windows computer, fuck it! Trust us, this is <em>wayyyy better</em>!</li>
<li>Ok, so since we&rsquo;re not doing this like you would expect, you&rsquo;re probably confused by what&rsquo;s happening now. So we&rsquo;re going to give you a link to a <a href="http://www.adobe.com/products/reader/dlm/firefox_steps.html">page that&rsquo;s going to make you more confused</a>! Oh yea, we&rsquo;re going to make you edit Firefox options that you didn&rsquo;t know existed. We&rsquo;re also going to show you instructions for an old version of Firefox (we know, Firefox 2 came out 4 years ago, but it&rsquo;s still awesome!), so those pictures don&rsquo;t match up with what&rsquo;s actually happening to you. Oh and one more thing. We know you&rsquo;re installing Flash, but these instructions are for Adobe Reader. I mean, they&rsquo;re the same, so that big title that says &ldquo;Adobe Reader Installation Instructions&rdquo; shouldn&rsquo;t confuse you at all. If it does, you&rsquo;re dumb!</li>
<li>Our bad, just click that &lsquo;Allow&rsquo; button up at the top of Firefox, but under the tabs. It&rsquo;s a little yellow. It&rsquo;s really easy to see. Found it yet? No? That&rsquo;s cool, I guess we didn&rsquo;t explain this very well. Moving on.</li>
<li>Sweet, so now we&rsquo;re installing an extension! WOOOOO!! It&rsquo;s called &#39;Adobe DLM&rsquo;, not Flash. Oh you didn&rsquo;t read the fine print? Yea we said we might use the Adobe Download Manager, so we&rsquo;re doing that. But we didn&rsquo;t actually want to say &#39;Download Manager&rsquo; when you were installing - we thought that might get confusing.</li>
<li>Right, so since this is a Firefox extension, we&rsquo;re going to need you to restart Firefox. I mean, we needed to do that anyway, so let&rsquo;s just get it out of the way. Go ahead, you definitely want to do that. BUT we&rsquo;re going to make you figure that out yourself. Oh? You didn&rsquo;t notice that little bar in Firefox that said you need to restart? Oh well. Find it and press it. We&rsquo;re almost done now!</li>
<li>So now you&rsquo;ve restarted Firefox, you get an <em>awesome</em> Windows alert asking if you want to let Adobe DLM make changes to your computer. You definitely want to press &#39;Yes&rsquo;. Still with us? Ok, so just let Adobe Download Manager do it&rsquo;s thing (yes, DLM is an abbreviation for &#39;Download Manager&rsquo;, you didn&rsquo;t figure that out on your own?).</li>
<li>And we&rsquo;re done!</li>
<li>By the way, we&rsquo;re just going to leave this extension installed. That way when we want to fuck you in the ass, we can. Have a nice day ;)</li>
</ol>
<p><strong>FUCK YOU ADOBE!</strong></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/K_xIowV1IdA" height="1" width="1" alt=""/>The Muni Death Spiral2010-04-14T00:00:00-07:00https://zpao.com/posts/the-muni-death-spiral<blockquote>
<p>&hellip; Muni spends more to operate its vehicles than virtually any comparable transit agency. For every mile Muni runs a bus in this city, it spends $19.21; comparable agencies nationwide pay between $10 and $13. For every mile Muni runs a light-rail vehicle, it throws down $24.37; comparable rail services spend between $12 and $22.</p>
</blockquote>
<p>Those are frightening numbers.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/e4odoy4tbgs" height="1" width="1" alt=""/>JAQK Wine Cellars&rsquo; Bottles2010-04-11T00:00:00-07:00https://zpao.com/posts/jaqk-wine-cellars-bottles<p><a href="/img/posts/originals/jaqk.png"><img src="/img/posts/jaqk.png" alt=""></a></p>
<p><a href="http://jaqkcellars.com/">JAQK Wine Cellars</a> has the most fantastic wine bottle design I&rsquo;ve seen. The <a href="http://jaqkcellars.com/wine-jaqk-cellars-wine-collection-napa-valley-sonoma-coast/high-roller">High Roller</a> literally has a poker chip in the bottle. It&rsquo;s not all just good looks though, it&rsquo;s also pretty delicious wine.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/6o1KR3RAJBo" height="1" width="1" alt=""/>The Cat With Hands2010-04-09T00:00:00-07:00https://zpao.com/posts/the-cat-with-hands<iframe width="640" height="360" src="http://www.youtube.com/embed/n4PR9NZlAB4?rel=0" frameborder="0" allowfullscreen></iframe>
<p>It&rsquo;s incredibly well done but as said <a href="http://www.reddit.com/r/WTF/comments/bom8g/the_cat_with_hands_unsettling/c0nseoo">here</a>: <em>fucking unsettling</em>. If you nightmare easily, don&rsquo;t watch it before bed, especially if you have a cat.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/1HwRQ5fltag" height="1" width="1" alt=""/>On Rude Recruiters2010-04-09T00:00:00-07:00https://zpao.com/posts/on-rude-recruiters<p>Recruiters are part of how the world works. For the most part, I don&rsquo;t mind being contacted by them. They&rsquo;re doing their job. However, I do mind when they lack manners. I probably shouldn&rsquo;t complain that I&rsquo;m being contacted, but the lack of manners is one of my biggest pet peeves so I&rsquo;m bitching. Here&rsquo;s a few recent examples.</p>
<p>Last month I got one that included:</p>
<blockquote>
<p>If for some reason you are not interested &hellip;</p>
</blockquote>
<p>I think it&rsquo;s a bit presumptuous to assume I would be interested. It&rsquo;s probably a form footer, which doesn&rsquo;t make it any better.</p>
<blockquote>
<p>Currently I am crazy searching for 4 positions in the bay.</p>
</blockquote>
<p>This is the first sentence from somebody I haven&rsquo;t ever talked to. No &ldquo;Hello&rdquo;, no &ldquo;My name is _____ and I&rsquo;m reaching out to you because _____&rdquo;. Also, you&rsquo;re &ldquo;crazy searching&rdquo;? Really?</p>
<p>Earlier today I had somebody call my work extension (which is not in any public place that I know of, nor have I given it to anybody outside the company). How did she get my number? Not only that, but she flat-out lied about what is on my LinkedIn profile:</p>
<blockquote>
<p>I actually came across your LinkedIn profile and um&hellip; I see blatantly there that you&rsquo;re um&hellip; um&hellip; in a position to look for something new.</p>
</blockquote>
<p>Go ahead and look at <a href="http://www.linkedin.com/in/pauloshannessy">my profile</a>. If you see anything there that says I&rsquo;m interested in something new, let me know so I can remove it. I have zero plans to leave Mozilla.</p>
<p>Obviously not all recruiters are rude. I like to think we have an awesome recruiting team at Mozilla, and I&rsquo;ve been contacted by very polite people. I remember the nice ones and I&rsquo;ve even reached out to the some when friends have been looking for positions.</p>
<p>So recruiters, here are some simple rules for contacting people:</p>
<ul>
<li>Say some sort of greeting.</li>
<li>Introduce yourself, let me know where you work.</li>
<li>Tell me how you got my name/email/phone number, etc.</li>
<li>Then tell me about the awesome position that you think I&rsquo;m qualified for and will love.</li>
<li>DON&rsquo;T MAKE SHIT UP (especially about me, I mean seriously)</li>
<li>You&rsquo;re going to say &ldquo;if you know anybody else who might be interested please forward this along&rdquo; or something along those lines. We all know it.</li>
<li>If you&rsquo;ve done the above, I&rsquo;ll respond in a similarly polite fashion and maybe forward the position on to somebody who might be looking for a job.</li>
</ul>
<p><a href="http://freelancewritinggigs.com/businesstips/wp-content/uploads/2009/07/Dewey-Bridge-Fire.jpg">This is a picture of a burning bridge.</a></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/BMjjORtdJTE" height="1" width="1" alt=""/>The Rise &amp; Fall of Courant News2010-04-07T00:00:00-07:00https://zpao.com/posts/the-rise-fall-of-courant-news<p>I&rsquo;m only a couple months late with this&hellip; Hot on the heels of the <a href="http://www.copress.org/2010/02/16/copress-is-closing-down-operations/">announcement that CoPress was shutting down</a>, Max Cutler announced the <a href="http://www.maxcutler.com/2010/02/21/courant-no-longer">end of the Courant News project</a>. His post is a good read, and his blog in general has some great insight into the technology behind Courant. If you&rsquo;re at all interested in the future of online journalism, I highly suggest it. Since I have yet to blog about <a href="http://www.courantnews.com/">Courant News</a>, I feel like I must, so here&rsquo;s the story.</p>
<p>Courant News was an online newspaper project started in the fall of 2008. It was started by <a href="http://www.maxcutler.com/">Max Cutler</a>, <a href="http://rsbaskin.com/">Robert Baskin</a>, and myself out of our frustration with existing college newspaper technologies. Combined, we had ~8 years of working on college newspaper websites. Max and Rob both worked at the <a href="http://www.yaledailynews.com/">Yale Daily News</a> and I worked for The Carnegie Pulse (now dead and without a domain). We both worked on custom built PHP back-ends. Robert had helped write the YDN one, while I inherited TCPulse&rsquo;s (and had been wanting to rewrite it for years). Both worked, but were a bit rigid for the needs of an online newspaper.</p>
<p>We started this project and settled on <a href="http://www.djangoproject.com/">Django</a> as a technology choice. I was a Rails guy, while Max was the Django advocate. We chose Django because of it&rsquo;s journalism roots, my admission that I was going to have less time, and the fact that this really was Max&rsquo;s project. After I got to play with Django, I think it was the right choice for the project. The ability to have separate &ldquo;apps&rdquo; was pretty awesome. And the built in admin app (which I thought was dumb at first) turned out to be pretty essential. All-in-all I have a lot of respect for <a href="http://www.youtube.com/watch?v=PLUS00QrYWw">DJ Ango</a>, and as the RailsEnvy guys said, &ldquo;If it wasn’t for Rails I’d probably be programming Django right now.&rdquo;</p>
<p>We talked a lot via Skype about various things and within a few weeks were hacking away. We had a basic version running pretty quickly - it doesn&rsquo;t take much to make something that serves content. We had various architecture discussions (hosted SASS? one large app with domain handling vs a separate instance per hosted site, etc), all of which were awesome to have. It felt great to be making something and talking with smart and passionate people.</p>
<p>Probably the best part (technologically) was the idea of the &ldquo;get&rdquo; tag. I won&rsquo;t explain it too much here, but in short it was a way to make Django&rsquo;s template system even easier to use for designers. We were building this so that not-so-technically-inclined newspaper editors could make quick layout edits in relatively sane way. If you&rsquo;re interested, <a href="http://docs.courantnews.com/ref/core/gettag.html">read more in the docs</a>.</p>
<p>Eventually we got to really thinking about the viability of the project from a business stand point. It was now early 2009. I was getting ready to start full-time at Mozilla, Rob was going to be starting at Microsoft in a few months, and so we really had to evaluate where it was going. There was a legitimate concern about non-competes (more so for Rob), not to mention time constraints. There was also the issue about how we would make money. We crunched the numbers and it wasn&rsquo;t convincing enough to risk losing our well-paying jobs.</p>
<p>So we decided to open source the project. We talked with the CoPress people and with college newspaper editors and developers around the country. There was certainly interest in using such a project. Especially with the whole Knight Foundation sponsored <a href="http://www.populousproject.com/">Populous Project</a> (which was supposed to be open source and awesome) going nowhere. The problem though is that there aren&rsquo;t many people actually interested in working on the project.</p>
<p>So we put the code out there exactly 1 year ago. I really didn&rsquo;t have a whole lot of time to keep going, so Max and Rob continued to work on it, getting it ready to power The Yale Daily News. Originally targeted for late spring 2009, that slipped to the beginning of the fall semester. Max deserves a huge amount of credit here. While it was still using the stock Django admin, it was powering a major college newspaper. Not just powering, but <a href="http://www.maxcutler.com/2009/09/23/keeping-courant-with-annie-le-coverage">standing up to a huge spike during a breaking nation news story</a> and allowing editors to do things they hadn&rsquo;t been able to do before.</p>
<p>Still though, nobody else was working on it. Max and Rob had continued doing some additional work, but with Max&rsquo;s term ending at YDN and Rob working full-time, it was getting unreasonable. So Max and Rob made the decision to stop working on it and just let it run free.</p>
<p>A lot of hard work went into Courant News. If this were several years ago, I&rsquo;d still be working on it, but I think in the end, we all did what we needed here. It was fun while it lasted.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/vUMYH0bsBPE" height="1" width="1" alt=""/>Shaver Facts2010-03-26T00:00:00-07:00https://zpao.com/posts/shaver-facts<p><a href="/img/posts/originals/shaver-facts.png"><img src="/img/posts/shaver-facts.png" alt=""></a></p>
<p>I had absolutely nothing to do with <a href="http://shaverfacts.com">shaverfacts.com</a>. Absolutely nothing.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/SS0J2ZhwuII" height="1" width="1" alt=""/>Fuckin&rsquo; Style. And Futura. And HTML5.2010-03-18T00:00:00-07:00https://zpao.com/posts/fuckin-style-and-futura-and-html5<p>I&rsquo;ve been wanting to redesign my blog for a while. Back on the <a href="http://zpao.com">old blog</a>, I still have the same theme as I made <a href="/posts/new_design_updates">a year and a half ago</a>, which for me is pretty impressive. I tend to redesign at the drop of a hat, work on it for a while, then forget about it. Eventually I&rsquo;ll spend a day on a completely different design and that&rsquo;s what I use.</p>
<p>When I started <a href="/posts/tumbling-down-the-rabbit-hole-again">using Tumblr for blogging</a>, I wanted to make it look slick. But I didn&rsquo;t have the time, so I went with <a href="http://www.tumblr.com/theme/1909">the cleanest pre-made theme I could find</a>. It worked well, and I was just going to tweak it. But then I decided I wanted to see what the buzz was about HTML5. So I rewrote that theme with the appropriate <code class="prettyprint">&lt;article&gt;</code>, et al. tags and my own, cleaner CSS. But it didn&rsquo;t feel right. So I started over with minimal markup with no style, and just played with it. I still drew inspiration from that theme, but that&rsquo;s ok.</p>
<p>Anyway, it&rsquo;s a work in progress. I won&rsquo;t post about it again, but you may notice things change or break as I tweak it (or add features, like pagination or conversation posts). If you love <a href="http://static.zpao.com/tumblr/future.css">clean, structured CSS</a> with variables, check out <a href="http://sass-lang.com/">Sass</a>.</p>
<p>Also, if you don&rsquo;t have Futura and you just see Helvetica (or even Arial), I&rsquo;m sorry. It looks way better for me.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/zG8RrvIe5-g" height="1" width="1" alt=""/>(Partially) Dropping Support for Firefox 2.0/3.0 Sessions2010-03-15T00:00:00-07:00https://zpao.com/posts/partially-dropping-support-for-firefox-2-0-3-0<p><strong><em>Note: This does not affect Firefox 3.5 or 3.6 users!</em></strong></p>
<p>Today <a href="http://hg.mozilla.org/mozilla-central/rev/55b6bc4c0b92">I landed a patch</a> for <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=551285">bug 551285</a>, which removes support for certain parts of sessions created in Firefox 2.0 and 3.0. <em>This means that if you upgrade directly from 2.0 or 3.0 to Firefox.next (currently 3.7), you will lose some session data.</em></p>
<p>The data you would lose is limited to the following:</p>
<ul>
<li>Form data (2.0 and 3.0)</li>
<li>Session Cookies (2.0 only)</li>
<li>Tab XUL Attributes (2.0 and 3.0)</li>
<li>Session History Post Data (2.0 only)</li>
<li>Session History Owner (2.0 only)</li>
</ul>
<p>If losing any of this data particularly bothers you, then it&rsquo;s as simple as upgrading to <a href="http://www.mozilla.com/en-US/firefox/firefox.html">Firefox 3.6</a> or <a href="http://www.mozilla.com/firefox/all-older.html">Firefox 3.5</a> first. Alternatively, some session management add-ons could update your session file for you (for example, the author of <a href="https://addons.mozilla.org/en-US/firefox/addon/2324">Session Manager</a> is updating his add-on to do that).</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/GWYpZNt4wmg" height="1" width="1" alt=""/>Gilbert Gottfried Introduces the Shoedini2010-03-14T00:00:00-08:00https://zpao.com/posts/gilbert-gottfried-introduces-the-shoedini<iframe width="640" height="480" src="http://www.youtube.com/embed/LBPAQ6CJvTo?rel=0" frameborder="0" allowfullscreen></iframe>
<p>Gilbert Gottfried introduces the <a href="https://www.tryshoedini.com/">Shoedini</a>. Until now, the only thing I&rsquo;ve liked him in was Aladdin.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/A7h5JUqG2B0" height="1" width="1" alt=""/>Carnegie Mellon Professor Calculates Real Risk of Driving a Recalled Toyota2010-03-12T00:00:00-08:00https://zpao.com/posts/real-risk-of-driving-a-recalled-toyota<blockquote>
<p>Consumers also may want to reconsider parking their recalled Toyotas until repairs have been made. &ldquo;Replacing driving by walking really increases the risk of dying,&rdquo; Fischbeck said. &ldquo;Walking a mile is 19 times or 1,900 percent more dangerous than driving a mile in a recalled Toyota. Driving while using a cell phone would increase risk much more than the chance of having a stuck accelerator.&rdquo;</p>
</blockquote>
<p>I&rsquo;m of the opinion that this whole thing is being blown way out of proportion. There may well be some problem, but I think that user error is at least partially to blame.</p>
<p>Another interesting read is this Washington Examiner OpEd: <a href="http://www.washingtonexaminer.com/opinion/columns/OpEd-Contributor/I-am-not-afraid-of-my-Toyota-Prius-87361597.html">Theodore H. Frank: I am not afraid of my Toyota Prius</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/kb-U7oHVlQw" height="1" width="1" alt=""/>Tumbling Down the Rabbit Hole (Again)2010-03-11T00:00:00-08:00https://zpao.com/posts/tumbling-down-the-rabbit-hole-again<p>If you&rsquo;ve followed my blogging habits, you&rsquo;ll know that I&rsquo;ve tried a bunch of different solutions (greymatter, livejournal, blogger, wordpress, etc.) before finally <a href="http://blarg.zpao.com/">rolling my own</a>. Wordpress lasted several years before being retired. Then I tried tumblr. It was a cool concept, but I ended up just pulling in twitter &amp; photo feeds and that got messy. I finally built my own and have been really happy with it, but I feel like every post there needs to be important &ndash; it feels too serious. The other problem I have is that I just don&rsquo;t have the time to tinker as much as I used to. Having a full-time job is <em>(SURPRISE!)</em> time consuming. By the time I&rsquo;m home I just want to relax and get away from my computer. If I want to write something, I just want it to be easy.</p>
<p>Now I&rsquo;m back on tumblr with the hopes that I have more fun with it. As <a href="http://cameronmoll.tumblr.com/post/434902312/new-design-new-host-and-tumblr-how-why">Cameron Moll said the other day</a>, I really like the idea of mixing interesting links with full content that <a href="http://daringfireball.net/">John Gruber</a> and <a href="http://kottke.org">Jason Kottke</a> do so well.</p>
<p>So I&rsquo;ll be doing just that: sharing cool things, thoughts that are too long for twitter, and maybe some full-length articles. I haven&rsquo;t decided if I&rsquo;ll be posting my work-related status reports here (it&rsquo;s something we do now, but I&rsquo;ve been terrible about) or if those would be better elsewhere. I&rsquo;ll make that call&hellip; tomorrow.</p>
<p>I&rsquo;ve kicked off the fun by <a href="http://zpao.tumblr.com/post/442212843/my-desktop-makes-me-happy-no-menu-no-icons-on">showing off my desktop</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/PGeKdhU0GMc" height="1" width="1" alt=""/>My Desktop Makes Me Happy2010-03-11T00:00:00-08:00https://zpao.com/posts/my-desktop-makes-me-happy<p><a href="http://www.flickr.com/photos/zpao/4426175014/" title="My Minimal Desktop by zpao, on Flickr"><img src="https://farm5.staticflickr.com/4051/4426175014_3e466c96f4_z.jpg" width="640" height="400" alt="My Minimal Desktop"></a></p>
<p>My desktop makes me happy. No menu, no icons on the desktop, no dock. Minimal.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/E2tfIcWpDVM" height="1" width="1" alt=""/>Just Released: Always Ask2009-12-21T00:00:00-08:00https://zpao.com/posts/just-released-always-ask<p>No, I didn&rsquo;t mean to press ⌘Q, I just wanted to close that tab. Sure, all I have to do is start Firefox again. You&rsquo;re right, I didn&rsquo;t really need those minutes of my life. Yea, go ahead and install those updates I intentionally was putting off. I probably didn&rsquo;t lose any important information. Oh wait, Session Restore doesn&rsquo;t save form data on https sites (read: Bugzilla) by default? <strong>FFFFFFFFFFFFUUUUUUUUUUUUUUUUUU!!!!!!</strong></p>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/55824/">Always Ask</a> is an add-on that adds an additional prompt to Firefox when you are quitting. The prompt only shows up if Firefox has determined that you don&rsquo;t need a prompt. This includes when you have <a href="http://support.mozilla.com/en-US/kb/Session+Restore">Session Restore</a> enabled, if you&rsquo;ve changed either of the <code class="prettyprint">browser.warnOn*</code> prefs, or if you don&rsquo;t have Session Restore enabled &amp; are closing multiple tabs. There&rsquo;s probably some other combination of conditions that change the outcome here.</p>
<p>Since I work on Session Restore, I&rsquo;ve had it turned on for a long time. In the past I&rsquo;ve intentionally changed my preferences so that it wouldn&rsquo;t automatically quit, but that has led to me accidentally setting prefs and disabling the prompt. Then I have the same problem.</p>
<p>So this extension is pretty simple. It&rsquo;s currently available in English (en-US) but if you&rsquo;d like to see it in your language, feel free to <a href="http://www.babelzilla.org/index.php?option=com_wts&amp;extension=5271">help out on Babelzilla</a>. Code is available <a href="http://github.com/zpao/alwaysAsk">on Github</a> (thanks to hg-git).</p>
<p><img src="https://farm3.static.flickr.com/2682/4203971167_45d442d2eb.jpg" alt="Always Ask in action"></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/7ojoSIZRYzc" height="1" width="1" alt=""/>Status Update: November 9, 20092009-11-09T00:00:00-08:00https://zpao.com/posts/status-update-nov-09-2009<p>Not much exciting happened this past week. We had some out-of-towners (<a href="http://beltzner.ca/mike">beltzner</a>, <a href="http://blog.johnath.com/">johnath</a>, and <a href="http://autonome.wordpress.com/">dietrich</a>) down in the Mountain View office. It’s good to see the boss face-to-face every once in a while. Otherwise it was business as usual.</p>
<h2>What I got done last week:</h2>
<ul>
<li><strong><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=522545">Bug 522545</a>:</strong> Third time’s the charm. I finally found an acceptable approach to solving the problem. The problem of… ZOMBIE TABS. Interestingly, this bug is fallout from a different bug I worked on. Read the bug for full details.</li>
<li><strong><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=525635">Bug 525635</a> &amp; <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=521233">Bug 521233</a>:</strong> Both of these are needed to get Per Tab Network Prioritization into Firefox 3.6. Bug 525635 was about the test that was randomly timing out on Linux. It’s using the test framework added in bug 521233 (waitforFocus in browser-chrome tests), which obviously is not quite right. <a href="http://design-noir.de/log">Dão</a> is continuing to try to find the right fix, but until then, I’ve worked around the issue in a better way than I was. This should make it OK to land everything needed on branch.</li>
</ul>
<h2>What’s happening this week:</h2>
<ul>
<li>Finish bug 522545. Blockers come first. I already have a large portion of the work done &amp; have a good start on tests, so this shouldn’t be too much work.</li>
<li>Land Per Tab Network Prioritization on branch. Not too much involved here, but it has to happen.</li>
<li>Work on <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=526545">bug 526545</a> (Crash reporter still can send wrong URL when crashing during pageload). This is another blocker. The partial solution should be pretty easy and actually dovetails nicely with the work I’m doing for bug 522545. The full solution might be a bit harder, and might not be worth it.</li>
</ul>
<img src="http://feeds.feedburner.com/~r/zpao/~4/Swn06bYXAeM" height="1" width="1" alt=""/>Per Tab Network Prioritization Update2009-10-30T00:00:00-07:00https://zpao.com/posts/per-tab-network-prioritization-update<p>Progress on this was not as fast as I’d hoped it would be. It got stalled behind some other work, going to the CMU job fair, <a href="http://twitter.com/zpao/status/5076044119">I was poisoned</a>, and I had to figure out how the focus tests work. But that’s enough with the negativity, this is supposed to be good news.</p>
<p>I finally got all my ducks in row and <a href="http://hg.mozilla.org/mozilla-central/rev/bbeaa4e518ee">landed the feature today</a>! If you don’t remember what the feature does (or never knew), read through <a href="/posts/per-tab-network-prioritization/">my original article on it</a>. While the underlying implementation changed a fair amount, the basic concept is still the same. The only change made is that we adjust the priority instead of just changing it to pre-determined values. By doing it this way, we won’t interfere with an add-on that, for example, gave Gmail a super high network priority.</p>
<p>We’ve talked about getting this into Firefox 3.6. It’ll need to “bake” a little while on trunk, but it landed cleanly and doesn’t have any compatibility issues, so it should be ok. Then again, <abbr title="I Am Not A Driver">IANAD</abbr>.</p>
<p>Going along with this, I’ve updated the <a href="https://addons.mozilla.org/en-US/firefox/addon/14138">mozNetworkPrioritizer extension</a> to reflect the change in compatibility. It should no longer be used with Firefox 3.7a1pre (and beyond). It will interact poorly with the built-in functionality and could lead to some weird priorities. It won’t actually break anything, but there’s no need to use it. I’ll release another update if/when this goes into Firefox 3.6.</p>
<p>And that’s it. I’ll post again about future landings. Otherwise, I’m going to be working on some session restore blockers and starting another project soon.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/Q4_OZXKhgqQ" height="1" width="1" alt=""/>Status Update: September 25, 20092009-09-27T00:00:00-07:00https://zpao.com/posts/status-update-sept-25-2009<p>I haven’t updated on the blog recently, so here’s the past 3 weeks all at once.</p>
<p>The week of September 7, I was working on a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=514751">couple</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=497730">blockers</a>.</p>
<p>The week of September 14, I was in Pittsburgh recruiting at the Carnegie Mellon <abbr title="Technical Opportunities Conference">TOC</abbr> (job fair). I also did some work on Per Tab Network Prioritization (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=514490">bug 514490</a>) and a password manager performance bug (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=492197">bug 492197</a>).</p>
<p>This past week I worked on a few different things. I finished the password manager bug (which I hadn’t finished because of a non-syntax-error-syntax-error). While helping <a href="http://www.hskupin.info/">Henrik</a> as he was using the storage API, <a href="http://shawnwilsher.com/">Shawn</a> mentioned that one of the methods I used was deprecated (though never explicitly). So I filed <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=518434">the bugs</a> and <a href="http://hg.mozilla.org/mozilla-central/pushloghtml?changeset=5e6a413226d2">fixed the places</a> that used the deprecated code (hint: use <code class="prettyprint">executeStep()</code> instead of <code class="prettyprint">step()</code> and don’t use <code class="prettyprint">mozIStorageStatementWrapper</code>). Filing the bugs took longer than fixing them.</p>
<p>But all of that was unrelated to …</p>
<h2>Per Tab Network Prioritization Status</h2>
<h3>Progress</h3>
<ul>
<li>Made it a JS module. This was advice from <a href="http://autonome.wordpress.com/">Dietrich</a> to cut down on overhead. Since it was only being used from JS code, there was no need to use XPCOM.</li>
<li>Made it pref enabled. Right now it’s <code class="prettyprint">browser.networkprioritizer.enabled</code> but that’s easy to change.</li>
<li>Got a first pass look from Shawn, fixed a few things up.</li>
</ul>
<h3>Next Steps</h3>
<ul>
<li>Reviews. It seems like Boris is the guy for the job. Still need a browser person. Gavin said sometime after Fennec stuff, Connor said 2 weeks. Dolske said “soon”, so he’ll probably be the lucky guy, even if he isn’t a peer.</li>
</ul>
<img src="http://feeds.feedburner.com/~r/zpao/~4/XgpTGuVY4WI" height="1" width="1" alt=""/>Per Tab Network Prioritization2009-09-04T00:00:00-07:00https://zpao.com/posts/per-tab-network-prioritization<p><strong>First!</strong> (before you get distracted) <a href="https://build.mozilla.org/tryserver-builds/poshannessy@mozilla.com-try-11a9e78a8cb5/">Try server builds!</a> and <a href="https://addons.mozilla.org/en-US/firefox/addon/14138/">the extension!</a> (Firefox 3.5+)</p>
<h2>The Idea In Summary</h2>
<p>An idea that’s likely been tossed around before has been brought to the forefront more recently by Firefox’s newest designer <a href="http://limi.net/">Alexander Limi</a>, the idea of <a href="https://wiki.mozilla.org/Firefox/Projects/Per_Tab_Network_Prioritization">per tab network prioritization</a>. The premise of the idea is that what you’re doing right now is more important that what you were doing 5 minutes ago. So to account for the relative importance, we should make what you’re looking at right now load faster. This is really part of a grander scheme to improve perceived performance, but has been reduced to try to make some improvement achievable for Firefox 3.6.</p>
<h2>In More Detail</h2>
<p>For this pass, we divided tabs into level of importance (shown in descending order):</p>
<ul>
<li>Selected Tab in a Focused Window</li>
<li>Background Tab in a Focused Window &amp; Selected Tab in a Background Window</li>
<li>Background Tab in a Background Window</li>
<li>Any Tab in a Minimized Window</li>
</ul>
<p>For the most part that makes sense, except for maybe one thing: the 2<sup>nd</sup> level of importance has 2 items. We decided that (at least in general terms) background tabs in your current window and the focused tab in a background window should get the same level of network priority.</p>
<p>I then used this ranking to assign relative priorities. You can read more in the implementation section, but otherwise you can skip down to the progress report.</p>
<h2>Implementation</h2>
<p>My original plan was to do this all in browser/base/content (browser.js, tabbrowser.xml), but I ran into a roadblock of some sort. So I wrote it as an extension. After fixing an observer topic, I could do this with relative ease. I set my JS up much like the SessionStore component, observed a number of topics, and listened for a number of events. I was using an observer topic (xul-window-visible) which I was told I shouldn’t use. When a tab was selected it’s network priority gets bumped up and the previously selected tab gets dropped down. Same concept for windows.</p>
<p>I had to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=511503">create some new events</a> so that I could accurately know which window was focused. Then I brought it into our actual tree instead of living externally as an extension. I cleaned it up a bit, made sure I wasn’t doing to too much, and then finally got around to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=514490">filing the bug</a>. I would go into further detail, but it’s not super interesting. However, if you are interested, <a href="https://bugzilla.mozilla.org/attachment.cgi?id=398441&amp;action=diff#a/browser/components/networkprioritizer/src/nsNetworkPrioritizer.js_sec1">take a look at the code</a>.</p>
<p>While there are some implementation details to improve upon (or just straight up change), it’s doing what it was supposed to be doing. At this point I could move this back into browser/base/content but since it’s working, there’s no value in it (until we decide the project is a final go).</p>
<h2>Progress Report</h2>
<p>Initial results showed some improvement when loading large groups of tabs. It was most noticeable when loading many tabs from the same site (e.g. the default BBC livemarks). It was somewhat noticeable during a typical (for me) session restore. There was no difference during normal browsing.</p>
<p>But I’m just one person. I know this is all the way at the bottom of this article, but <strong>PLEASE PLEASE PLEASE use <a href="https://build.mozilla.org/tryserver-builds/poshannessy@mozilla.com-try-11a9e78a8cb5/">a try server build</a></strong> (or <strong><a href="https://addons.mozilla.org/en-US/firefox/addon/14138/">the extension</a></strong>) for a little bit and see if there’s any noticeable difference. Even if it’s just to load up that 500 tab session you’ve been building up over the years.</p>
<p><strong>Next Steps:</strong> Get Feedback! If people use it and the results are positive, this will get more attention (tests, better implementation, checked in). If it turns out that we didn’t quite achieve what we were hoping, then this will get shelved or used as part of another project.</p>
<p>So again: <strong><a href="https://build.mozilla.org/tryserver-builds/poshannessy@mozilla.com-try-11a9e78a8cb5/">try server builds</a></strong> and <strong><a href="https://addons.mozilla.org/en-US/firefox/addon/14138/">the extension</a></strong>!</p>
<p><em>Updated September 4<sup>th</sup> with links to the extension</em></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/1JpKUuEQtHY" height="1" width="1" alt=""/>Oops, I Broke That2009-08-28T00:00:00-07:00https://zpao.com/posts/oops-i-broke-that<p>While making the “Set as Desktop Background” feature work on Windows CE, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=512524">I accidentally broke it on other Windows systems</a>. OOOOOPS.</p>
<p>This went unnoticed for ~3 weeks on the nightlies! It was even in Firefox 3.6 alpha 1. The fix was easy and was checked into trunk today. It’ll be checked into the Firefox 3.6 branch soon.</p>
<p>I don’t think mistakes like that are too uncommon, especially in areas where testing isn’t automated. We probably have <a href="https://litmus.mozilla.org/">Litmus tests</a> for this so it would have been caught before a final release anyway, but still…</p>
<p>This just goes to show how important testing is! (And yes, I <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=513349">filed a bug</a> to add tests here)</p>
<p>This also goes to show just how little people use that feature :)</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/1trzkKeUnsk" height="1" width="1" alt=""/>Better Session Restore Behavior2009-08-06T00:00:00-07:00https://zpao.com/posts/better-session-restore-behavior<p>Last week <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=354894">bug 354894</a> <a href="http://hg.mozilla.org/mozilla-central/rev/cd25ab8c2f30">landed</a> to, surprisingly, little fanfare. It’s a big deal though (more so on Windows &amp; Linux).</p>
<p>Ever since Firefox introduced Session Restore, there has been one particularly annoying problem: if you close your last browser window but accidentally left a non-browser window open (eg. Downloads), then your session was fucked. End of story.</p>
<p>Well, no longer. Nils Maier (co-author of <a href="http://www.downthemall.net/">DownThemAll</a>) finally got fed up with this problem &amp; decided to do something about it. This is the first “major” piece of code he’s contributed, so a round of applause.</p>
<p>A super quick summary of the changes (assuming you have enabled session restore):</p>
<ul>
<li>If you leave a non-browser window open, just close it. Your session will be saved (assuming you aren’t on OS X anyway).</li>
<li>If you’ve gotten down to that last non-browser window &amp; realized your mistake, opening Firefox again (e.g. from the start menu) reopens your last closed window.</li>
</ul>
<p>As a tangential comment, it’s things like this that really make me proud to be a part of the Mozilla community. So much of our browser &amp; platform comes from people like Nils who give their time freely to help make the web a better place.</p>
<p><strong>Update:</strong> Minor changes based on email with Nils.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/y2s5NiyIg8M" height="1" width="1" alt=""/>Undo Close Window Has Landed!2009-04-24T00:00:00-07:00https://zpao.com/posts/undo-close-window-has-landed<p>I’m happy to announce the landing of <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=394759">Undo Close Window</a>. This adds a menu &amp; keyboard shortcut for reopening your previously closed windows. By default we store 3 windows (though sometimes more due to special cases involving pop-up windows). I’m not going to go into further implementation details (because really, I know you don’t care), but if you’re interested, you can take a look at the patches on the bug.</p>
<h2>A Little History</h2>
<p>Sometime before Firefox 2, there were APIs in place for handling recently closed windows. The only thing missing at that point was the front-end work to tie it together. But that never happened. Instead, since the code wasn’t even being published for extensions to use, all that was happening is that we were eating memory for no good reason. So the <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=344642">code was taken out</a> late in the 2.0 development cycle.</p>
<p><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=360408">Bug 360408</a> was added for Firefox 3, making it possible for extensions to be able to implement their own Undo Close Window if they wanted. The description of that bug was unclear though, since it didn’t actually adding any APIs, it just made sure the data was kept around long enough to be saved by somebody else.</p>
<p>Along comes <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=394759">Bug 394759 - Add undo close window feature</a>, which sat untouched for almost a year. After I finished the <a href="/posts/passwordmgr-storage">primary project I worked on during my internship</a>, I still had a week left, so I looked for bugs that I found interesting and allowed me to explore a new area of the code. I found this bug and wrote a “working” patch over a weekend. At that point I was really surprised that we didn’t have this already. We’ve had Undo Close Tab for a while, and this seemed like the sensible next step. In all honesty, somebody familiar with the code involved here could have written that patch in an hour or two. That’s when I found out that I had essentially reimplemented the code that had been taken out and added the front-end to it.</p>
<p>I worked on it a bit more before I was done interning, then went back to school and time to work on this became increasingly rare. I dropped the ball a bit, and then suddenly we were at string freeze, and this wasn’t done. Fast forward a few months; I graduated &amp; started working for Mozilla full time. I found out we were still going to have another string freeze for beta 4, so I got my patch out of bitrot and continued working on it. It needed more work and testing by then due to Private Browsing and a few other changes that were made. Strings went in right before we froze them &amp; the actual patch went in very last minute, and only because code freeze had slipped for other reasons.</p>
<p>A huge thanks to Simon for all the reviewing he did and help he gave me, <a href="http://autonome.wordpress.com/">Dietrich</a> for the heroic “today is code freeze” review and help, <a href="http://en.design-noir.de/">Dão</a> for fixing the problems that popped up as this had a rocky landing (there was no time to bake on trunk), and <a href="http://beltzner.ca/mike/">Beltzner</a> for approving this without the normal bake time.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/MFZ-ten0jCE" height="1" width="1" alt=""/>Changing Tab Load Order2009-04-01T00:00:00-07:00https://zpao.com/posts/changing-tab-load-order<p>During the Firefox work week last month, somebody had the idea of loading visible tabs first. It’s one of those things that just make sense. Since I had done some work in the SessionStore component before, I volunteered to head up this task.</p>
<h2>What does it do exactly?</h2>
<p>When you open Firefox using session restore (and through some other paths), you often load several tabs. I know I’ve personally restored windows with 50+ open tabs. It takes a lot of time to load 50 tabs. One optimization that was done previously was to (roughly speaking) prioritize the selected tab, so that it would in theory load first. This change make it so that the tabs visible in your tab strip are also prioritized.</p>
<h2>How does it work?</h2>
<p>When we were doing this for just the selected tab, it was extremely simple - we just reordered the array of tab data so that the selected one was first. Now we prioritize a set of tabs (keeping the selected tab first). <em>That’s it.</em></p>
<p><strong>To be clear</strong>, this does not <em>actually</em> improve performance. All it does is make the browser feel faster. But hey, isn’t that just as almost as important.</p>
<p>Go ahead and try it out. It’s been in Minefield (mozilla-central) for over a week and landed in Shiretoko (mozilla-1.9.1) yesterday.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/pkflfXiRF2w" height="1" width="1" alt=""/>Is The Tree Green? For Your Desktop2009-03-24T00:00:00-07:00https://zpao.com/posts/is-the-tree-green-for-your-desktop<p><a href="http://projects.tynsoe.org/geektool/">GeekTool</a> is awesome. <a href="http://isthetreegreen.com">Is the Tree Green?</a> is awesome. So together they are SUPER AWESOME!</p>
<p><a href="http://www.flickr.com/photos/zpao/3382045487/"><img src="https://farm4.static.flickr.com/3588/3382045487_01114ff567.jpg" alt="isthetreegreen.py + GeekTool by zpao, on Flickr" title="isthetreegreen.py + GeekTool by zpao, on Flickr"></a></p>
<h2>Python?</h2>
<p>Historically, I’m a Ruby guy, but I started learning Python for a Django project I’m (barely) working on. So I picked up a book here at work &amp; decided to flex my pythons a little bit. You can laugh, it’s punny.</p>
<p>The first pass of this took me ~20 minutes, and I just tidied it up this morning so it would take command line options.</p>
<h2>How?</h2>
<p>If you’re reading this and actually need to know whether or not the tree is green, then you should be able to figure it out. GeekTool is OS X only, but there are similar programs for Windows and Linux.</p>
<p>It’s easy enough to do what I did in the image above. The program can take 2 arguments <code class="prettyprint">treename</code> and <code class="prettyprint">output</code>. Run it with <code class="prettyprint">-h</code> for usage.</p>
<h2>Code?</h2>
<script src="https://gist.github.com/84210.js">
</script>
<p>A big thanks to Justin Dolske for <a href="http://isthetreegreen.com">Is the Tree Green?</a>. He deserves more credit for this than I.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/dDWzFNMVlFo" height="1" width="1" alt=""/>Your Browser is Special2009-03-22T00:00:00-07:00https://zpao.com/posts/your-browser-is-special<p>Roughly 6% of the people visiting this site in the past month were using IE6. That’s mostly insignificant, but I despise IE6 and had to do my part to put an end to it. So, following in the footsteps of <a href="http://therissingtonpodcast.co.uk/">The Rissington Podcast</a> (and surely others), I’m serving up an IE6 stylesheet complete with Comic Sans. I also put together a super tiny script that puts a special message up top.</p>
<p><a href="http://www.flickr.com/photos/zpao/3376947996/"><img src="https://farm4.static.flickr.com/3559/3376947996_7b3fa08bc4.jpg" alt="Your Browser is Special by zpao, on Flickr" title="Your Browser is Special by zpao, on Flickr"></a></p>
<p>I’d been wanting to do this for a while, but it’s finally done. I’m using conditional comments to differentiate browsers. I used JavaScript to display the message so I wouldn’t be adding clutter to my source, even if nobody else would see it. View the source if you’re interested.</p>
<p>And yes, I’m biased about the browser I’m suggesting, but I’m allowed to be.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/ZuMXn3mq5vY" height="1" width="1" alt=""/>Here I Am, Back Again2009-03-10T00:00:00-07:00https://zpao.com/posts/here-i-am-back-again<p>I’m now into my third week here at Mozilla, working on Firefox. It’s been a tiring 2 weeks so far, but I’ve enjoyed every second.</p>
<p>For those of you who don’t know, I was an intern on the Firefox team last summer. I primarily worked on the password manager and a performance analysis tool. I was offered a full-time position soon after the summer ended, and while I did some looking around, I realized that I wanted to be at Mozilla. I loved the company, the people, and the work I would do — so overall it was right for me.</p>
<p>After an extended winter break, I flew out here with Amanda on February 17<sup>th</sup>, a Tuesday. Amanda had been looking at apartment stuff like a fiend, and while I helped, she found a bunch of great places for us to see and did the real work with that. So we spent Wednesday &amp; Thursday looking at ~20 apartments. CitiApartments may (apparently) be the spawn of Satan when it comes to housing in SF, but Hilary was an incredibly helpful agent, if perhaps a little unconventional. It turns out that the apartment we really wanted was the first one we saw on Wednesday morning. Friday was spent making sure our application went through, and jumping through hoops to get my money from my bank in Pennsylvania in order to get certified checks. It all worked out; we signed our lease on Saturday and moved in Monday/Tuesday. We’re working on making the place a bit more homey, but it’s coming along and hopefully we’ll have a little housewarming when there are places for people to sit.</p>
<h2>Back to Work</h2>
<p>I joined the team as we’re wrapping up Firefox <del>3.1</del> 3.5, and since I’m already relatively familiar with the code base, I got to start working on fixing blockers &amp; participating in <a href="https://wiki.mozilla.org/Firefox3.1/Sprints">sprints</a>. My first week was also a Firefox “work week,” where the Firefox team physically gets together (we’re spread out around the world), and gets stuff done face-to-face. We came up with a bunch of good ideas for what we want to be and how to make people excited about Firefox — that’s where our sprints came from.</p>
<p>I look forward to working with everybody here and meeting those of you who I haven’t met yet. Remember, I’m not an intern this time around :)</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/P4q3G8SQ1SI" height="1" width="1" alt=""/>YELL AT THE TV!2009-01-21T00:00:00-08:00https://zpao.com/posts/yell-at-the-tv<p><strong>FRESHLY LAUNCHED:</strong> <a href="http://yellatthetv.com">Yell At The TV!</a></p>
<p>I just launched a new app that lets you yell at your TV via twitter. It’s nothing fancy, but it was a good little bit of fun.</p>
<h2>Is LOST on yet?</h2>
<p>While this was an idea I had been kicking around for a while, it was the work done by Rick Olsen on <a href="http://islostonyet.com/">Is LOST on yet?</a> that made me decide to do this.</p>
<h2>Feature Poor</h2>
<p>It’s worse than feature poor right now. There’s only the first page right now.</p>
<p>Hopefully I’ll be adding features over the next week or so. The primary thing I want to add is some support for hashtags, allowing you to view tweets for a show, season, or episode. Something like #lost-s05e01. It shouldn’t be <em>that</em> much work, so hopefully I’ll find some time to do that.</p>
<h2>Dreamhost Pains</h2>
<p>I originally made this in <a href="http://sinatra.github.com">Sinatra</a>, but that didn’t work out so well on Dreamhost for a few reasons. I fucked around for a bit trying to get it to work, but gave up and instead rewrote it using Ruby on Rails. I really do like Dreamhost, but for projects like this, it’d be nice to host it with ease, using the framework of my choice.</p>
<p><strong>So give it a try: <a href="http://yellatthetv.com">http://yellatthetv.com</a></strong></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/CsxlJ5kIuDI" height="1" width="1" alt=""/>Hey Hey-ey, Goodbye2008-12-15T00:00:00-08:00https://zpao.com/posts/hey-hey-ey-goodbye<p>Today I took my last final exam as a Carnegie Mellon student. It’s been four and a half years, but it feels like just yesterday I got here. Pending that one last grade, today I became a <a href="http://ism.cmu.edu/">Master of Information Systems Management</a>. That degree joins my Bachelor’s degree I finished up in May. I could go on and on about the value of my education or spend time evaluating the programs I was in, but I won’t. I have a lot to say, so I’ll save it for another time. I mean this to be brief.</p>
<p>It’s often said that college changes you. <strong>It’s true.</strong> I really grew up here; or maybe matured. Either way, Carnegie Mellon has had a huge impact on my life. I figured out what I want to do with my life; I made good friends; I fell in love; <em>I learned</em>.</p>
<p>Now it’s time to move on, into the scary unknown of the real world. Working the ol’ daily grind, paying the bills, and so on. I’ll be far from my family and friends. I look forward to it though — it’s the next big adventure.</p>
<p><em>(Cue sappy music: “A Whole New World”)</em></p>
<p>Oh yea, did I mention that I’ll be working on <a href="http://getfirefox.com">the best damn browser</a> out there?</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/gthOfgWEVrg" height="1" width="1" alt=""/>Yahoo! HackU 20082008-10-12T00:00:00-07:00https://zpao.com/posts/yahoo-hacku-2008<p>This past week Yahoo! was on campus for their annual <a href="http://developer.yahoo.com/hacku/">HackU</a> event. This is the third year they have been doing it and each year it has gotten progressively larger.</p>
<h2>The Past</h2>
<p>The first year (2006), I think there was a single entry. I made it in time for the presentation and was pretty sad I hadn’t had a chance to make anything.</p>
<p>Last year, I made a determined effort and hacked together my own entry - <a href="http://playground.zpao.com/yweather">yWeather</a> - and contributed to <a href="http://flolcatr.com">flolcatr</a>. These were among the six or so entries from Carnegie Mellon. I didn’t win anything, though I’m still pretty proud of yWeather. There was a 24-hour hack session on the last night, but I’m pretty sure there was nobody there after midnight.</p>
<h2>This year</h2>
<p>This year there were 28 hacks! I was simply astounded at the number and variation of the entries this year. There were technically impressive hacks, humorous hacks, hacks that could change the web, and even some creepy hacks. We had some big hacker names from Yahoo! show up - <a href="http://lerdorf.com/">Rasmus Lerdof</a> (creator of PHP), <a href="http://kentbrewster.com/">Kent Brewster</a> (hacker extraordinaire), and my new pal <a href="http://paulisageek.com/">Paul Tarjan</a> (creator of Search Monkey). I think there were people who actually pulled off the 24-hour hackathon, staying up the whole night. I know Paul was there when I left around 6am.</p>
<p>Last year I took advantage of the time and spent the week working on my hack. This year I didn’t start until after midnight. I contributed a little bit to a hack (“lolmonkey”) with <a href="http://matttthompson.com/">Mattt Thompson</a> which uses <a href="http://developer.yahoo.com/searchmonkey/">Search Monkey</a> and creates an infobar in Yahoo! search results lolifying an image on the linked page. While not the craziest hack, we had fun with it. I think at this point we are both officially done creating tools/hacks that have anything to do with lolcats.</p>
<h2>Busses &amp; the Blueprint Framework</h2>
<p>The other hack that I worked on uses the <a href="http://mobile.yahoo.com/developers/roadmap">Yahoo! Blueprint framework</a> for creating mobile applications. While not the most technically advanced hack, I think it was one with the most immediate value. It was called “CMU Busses”, and simply tells you the next 5 busses leaving Carnegie Mellon in either direction. You can see a screenshot on the <a href="http://playground.zpao.com/bp_busses">project page</a>. This is something I’ve been wanting to make for a long time, and something I would actually use (no offense to the other hacks). This was a true “hack” - I’m scraping the PAT website with Ruby. My Ruby code is outputting PHP code (the departure times are hardcoded instead of doing a DB lookup). Then the rest of the script is using the PHP Blueprint framework that Yahoo! provides (after spending a while working it out).</p>
<p>I had originally planned to make this an iPhone application, but having never done Objective-C, I figured now wasn’t the time to start. I had also wanted this application to be able to detect the user’s GPS coordinates and find the closes 5 bus stops before showing departure times, but that had some barriers as well. In a future iteration hopefully we’ll see that. The Blueprint framework is supposedly also able to convert a Blueprint application to an iPhone application, but that has not been released to the public yet. When it is released, I think I may publish what I have now as a first iteration.</p>
<h2>Some Other Highlights</h2>
<p>I got to hang out with some great people throughout the week. I also got treated to a dinner for all of the former Yahoo! interns at Fuel &amp; Fuddle. It was a good time, getting to talk some technology and design with smart people.</p>
<p>As a result of working on the lolmonkey hack, Mattt and I were invited to dinner by Alicia at <a href="http://buglabs.net">Bug Labs</a>. They have a really cool product called BUG, which as they say on their website, “is a collection of easy-to-use electronic modules that snap together to build any gadget you can imagine”. I got to play with one and it’s really neat. I wish I had some spare cash to get one. They also have some of the coolest package design I’ve seen in a while. So if you’re interested in hacking hardware, take a look at them - they’re cool people with a cool product, hacking on open source hardware and software.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/n0pfTzW3o9c" height="1" width="1" alt=""/>Making the New Password Manager Storage Faster2008-08-28T00:00:00-07:00https://zpao.com/posts/passwordmgr-storage-faster<p>When I first wrote the new storage module for the Password Manager, I took a few “shortcuts,” trying to keep my code DRY. Partially this was because of the first patch by Mrinal Kant, but mostly it was because I like to reuse code. This bit us just a bit.</p>
<p>I mentioned in my <a href="/posts/passwordmgr-storage">first post about this change</a> that we were initially considerably slower in the critical <code class="prettyprint">countLogins</code> method. While it got improved before being checked in, it was still marginally slower (milliseconds on an abnormally large dataset).</p>
<p>As I said before, this was most likely since we were doing a <code class="prettyprint">SELECT *</code> on the <code class="prettyprint">moz_logins</code> table, and looping over the results and counting. This allowed me to reuse more code. Loops are a kind of slow, and since this was so important, I decided to speed it up.</p>
<p><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=451479">I filed a bug</a> just over a week ago entitled “storage-mozStorage should use COUNT in countLogins” - which pretty much explains what the solution to the above problem. I created a patch which essentially just switched the mosStorage module to use <code class="prettyprint">SELECT COUNT(1)</code>. I reran the performance tests I created and we’re doing much better now. There’s still a miniscule loss in speed from the legacy storage module, but at this point, we’ve done all that we can, and where the difference was milliseconds, its closer to millisecond.</p>
<p>This was <a href="http://hg.mozilla.org/mozilla-central/rev/ce557eb9ef4a">checked in</a> today (thanks Justin!).</p>
<p>And that’s it. I have another patch in the pipeline and hopefully I’ll have time to get it finished, approved, and reviewed for the freeze (whenever that is now).</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/nEeYVhci9hI" height="1" width="1" alt=""/>Password Manager now uses mozStorage2008-08-18T00:00:00-07:00https://zpao.com/posts/passwordmgr-storage<p>The other day <a href="http://hg.mozilla.org//mozilla-central/index.cgi/rev/c2f416981fa3">my patch landed</a> switching the Password Manager to use <a href="http://developer.mozilla.org/en/docs/Storage">mozStorage</a> (our wrapper around SQLite). <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=288040">The bug</a> had been up on Bugzilla for a long time, over 3 years, when I came across it at the end of June. I had been doing some Password Manager related work already by that point, so I decided I would do it. This is the story of that bug: the process, the hardships, the code (at least a bit). Keep in mind I was also doing work on my <a href="/posts/dtrace-treemaps-part-1">DTrace Treemaps</a> at the time, went to Summit, and encountered more edge cases than I wanted, so this took longer than expected.</p>
<h2>Quick Features &amp; Change Summary</h2>
<p>Some of this is discussed further down, so bear with me. One of the primary differences in the switch to using mozStorage is that we now store data in a database. Previously we were storing data in a text file, using lines and periods to separate data fields. Open <code class="prettyprint">signons3.txt</code> in your <a href="http://support.mozilla.com/en-US/kb/Profiles">profile directory</a> and take a look at it (assuming you’ve saved a password before). All information was kept in memory, and when a new password was saved, the whole file would need to be rewritten. The same thing happened if you ever removed a saved password. Using a database means that we don’t have to keep any (potentially) sensitive information in memory. It also means faster reading and writing since we don’t have to read the whole file every time. These speed boosts are apparent especially in the speed tests, attached to the bug and summarized below.</p>
<p>Since this is really just a drop in change that must implement an API, to the outside world nothing has changed. Although the inner workings are different, it’s the same to anybody who happens to use it (extensions or other parts of Firefox).</p>
<h2>v0.1 - The beginning</h2>
<p>I began work by really taking a look at the <a href="http://mxr.mozilla.org/mozilla-central/source/toolkit/components/passwordmgr/src/storage-Legacy.js">legacy storage module</a> to make sure I knew what was supposed to be happening. Then I looked at the initial attempts by other developers. The first attempts were made before Password Manager got rewritten, so those weren’t relevant. Mrinal Kant came in (over 2 years after the first patches) and wrote what I used as the basis for my code. I don’t think I ran it as it was, but it looked functional, at least at the core.</p>
<p>I actually started by just copying the legacy storage file, removing all of the code from methods that would need to be changed, and started fresh. I copied in some code from Mrinal’s work and used some of the conventions, but the bulk of it was rewritten. I opted to use the wrapper we have for Storage, which makes it easy to do parameter replacement. This also automatically binds the parameters to a type - so when you give it a string, it will ensure it’s treated as a string. It’s very handy.</p>
<p>This first version “worked” (at least as far as I remember), though it definitely had problems. I brought it up at our <a href="http://wiki.mozilla.org/Firefox3.1/StatusMeetings/">weekly status meeting</a> and it became one of the “nice to have” features for 3.1. That gave it some attention it needed and I got some quick feedback from <a href="http://shawnwilsher.com">Shawn</a> and <a href="http://blog.mozilla.com/dolske/">Justin</a>.</p>
<h2>v0.2 - Database details</h2>
<p>One of the primary changes here was some of the database stuff. Shawn had pointed out that I needed a way to version the database. All I had was a method to create the tables. In order to future-proof this, I needed to make sure the schema was stored somewhere and there was a procedure for migrating the database.</p>
<p>I took a look at <a href="http://mxr.mozilla.org/mozilla-central/source/toolkit/components/contentprefs/src/nsContentPrefService.js">nsContentPrefService</a> (which stores your preferences for specific sites, like remembering zoom settings) since that was another component using storage and written in JavaScript. I “hijacked” the code related to the database stuff, and modified it a bit to fit my needs.</p>
<p>The other major change here was to replace <code class="prettyprint">var</code> with <code class="prettyprint">let</code> - “<code class="prettyprint">let is the new var</code>” as my shirt says. A number of other changes were also made - cleaning up queries, hard-coding the table names, and making sure I was using statements correctly.</p>
<h2>v0.3, v0.4 - Cleanup &amp; Optimization</h2>
<p>These versions were pretty light - mostly involving cleanup. <code class="prettyprint">modifyLogin and the process involved got improved. I also reduced the number of queries we were making by hand and so all</code>SELECTs were done from just 2 places (one for each table).</p>
<h2>v0.5 - Importing</h2>
<p>v0.5 focused on importing from the legacy module. The basics were in the original code Mrinal wrote, but all of the edge cases were difficult to handle. The one case that caused a lot of problems were the “user has a master password, but presses cancel when we import”. We needed to handle that gracefully, and Justin and I decided the best way was to introduce a <code class="prettyprint">_deferredInit</code> method, which did the bulk of the initialization work. At the beginning of each public method, we then check the initialization state and try to import again. It can get annoying, but everything about the master password is annoying.</p>
<p>This also resulted in a couple bugs being spun off to help us with importing: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=449810">one bug</a> was just a few lines added to the legacy module and the password manager UI to handle an additional error, and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=449095">the other</a> was just to ensure the legacy module didn’t create an empty file if it was never used.</p>
<h2>v0.6 - Tests</h2>
<p>I finally got to writing the tests, which involved a lot of copy &amp; paste from the legacy tests, then making small modifications. It’s not the most efficient way, but it works ok. Since the mozStorage module works slightly differently, the code duplication is a necessity for now. In theory they can be cleaned up, but that’ll be a task for the next intern :)</p>
<p>At this point I thought I was pretty much done, and I was. There were still a few problems though, and also not quite enough test coverage.</p>
<h2>v0.7, v0.8 - Cleanup, Tests, Corrupt Databases</h2>
<p>v0.7 involved a lot of cleanup and adding tests. v0.8 was an important milestone in that I finally added the handling of a corrupt database. Before this point, if we encountered a corrupt database, we would fail and then as with a failed import, just try again and again. This was bad, really bad. So a “thank you” to Shawn for catching that. Now we backup the corrupt database and just create a new one. It should be difficult to get a corrupt database, but just in case (and to cover the case when people think they know what they’re doing, but don’t).</p>
<h2>v0.9, v1.0 - Performance</h2>
<p>In one of the recent status meetings, <a href="http://shaver.off.net/diary/">Mike Shaver</a> asked me about performance. At that point I hadn’t really done much except throw it up on the try server. The try server gives decent ball park figures, but it’s not perfect. So Justin worked on getting <a href="http://wiki.mozilla.org/StandaloneTalos">Standalone Talos</a> working while I wrote some XPC shell “tests”. I discovered that while we were generally faster - faster init, faster add, faster remove - we were considerably slower for <code class="prettyprint">countLogin</code>, which is a critical path, since it gets called on every page. Over 90% of the that time was actually spent initializing <code class="prettyprint">nsLoginInfo</code> objects (since I tried to reuse code). This got improved, though we are still a couple milliseconds slower. This could likely be improved a little bit since we are still doing a <code class="prettyprint">SELECT</code> and looping over the results. A little bit more work needs to be done that way, so making the query use <code class="prettyprint">COUNT</code> would cut that out. Maybe I’ll write another patch to do that before Beta 1. For now though, we’ll keep doing it how we’re doing it.</p>
<h2>And that’s all… almost</h2>
<p>After this got checked in, the Windows boxes turned orange on Tinderbox. This was because of the tests (trying to delete files). Justin and I thought we had a quick fix, committed that. As I was packing to come home, I got pinged on IRC since the boxes were still orange and it was my fault. So the tests for my changeset got backed out and we switched back to the legacy module, but the code was still in there.</p>
<p>On Sunday, my module <a href="http://hg.mozilla.org/mozilla-central/index.cgi/rev/063c145b2a09">was re-enabled</a> (thanks Justin!). There was <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=451040">another hiccup</a> related to packages-static, but that was fixed as well. If you have any problems <a href="https://bugzilla.mozilla.org/enter_bug.cgi?component=Password%20Manager&amp;product=Toolkit">please report them on Bugzilla</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/NF5-0BJSwZk" height="1" width="1" alt=""/>New Design &amp; Updates2008-08-17T00:00:00-07:00https://zpao.com/posts/new-design-updates<p>The night before heading to Whistler for <a href="https://wiki.mozilla.org/Summit2008">Summit</a> (it was awesome!), I started messing around in Illustrator. I came up with a little idea that I liked and decided to take it a step further, so I opened Photoshop and got to work. It progressed fairly well, so I started working on the HTML the next day. By the end of the plane ride to Vancouver I had a single page mostly done, with all the images and everything.</p>
<p>I was busy the next few weeks, so put it aside. When I flew home yesterday, I decided to actually make it work. So here it is. There are probably a few things I’ll tweak when I see them, but I hope to keep this for a while.</p>
<p>I also decided to actually write my own comment system. I was pretty unhappy with <a href="http://disqus.com">Disqus</a>. Disqus has potential, but it required more work than it took for me to write my own. I have a basic “human test” to prevent against spam. We’ll see how well it works. If you commented here previously, I’ve taken the liberty to copy your comment into the new system, adding a link to your website if I knew it.</p>
<p>I’ve wrapped up my summer with Mozilla, so I’ll have more content about what I did coming shortly.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/-tA7EDg-Rgc" height="1" width="1" alt=""/>DTrace and Treemaps: Part 12008-07-24T00:00:00-07:00https://zpao.com/posts/dtrace-treemaps-part-1<p>One of my goals for this summer at Mozilla was improving performance when Firefox starts. Admittedly, I’ve done nothing of the sort. Instead I’ve tackled this from a more general angle - making a tool that uses DTrace and creates a treemap of the output. This serves as a way of analyzing performance in a very visual way. Before I go further, a little background.</p>
<h2>DTrace</h2>
<p>“DTrace is a comprehensive dynamic tracing framework created by Sun Microsystems for troubleshooting system and application problems in real time.”<sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> It was originally in Solaris and OpenSolaris, but has since been ported to OS X and was <a href="http://arstechnica.com/reviews/os/mac-os-x-10-5.ars/5#dtrace">included in Leopard</a>. In a nutshell, it lets you take a look at the inner workings of applications and kernel activity, with a low overhead. You can do everything from looking at file IO to time spent in functions to analyzing system call times. It’s pretty powerful and I’ve only just touched the surface of it.</p>
<p>Developers at Mozilla have done a lot of work getting probes into Firefox so that we can take advantage of all DTrace has to offer. One of these places where probes have gone is into JavaScript execution. This opens up the doors to using DTrace to track what’s happening in JavaScript, which is especially useful at Mozilla since a lot of our front-end code is JavaScript.</p>
<h2>Treemaps</h2>
<p>“Treemapping is a method for displaying tree-structured data using nested rectangles.”<sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup> In other words, pretty damn cool. One of the coolest uses I’ve seen recently is <a href="http://marumushi.com/apps/newsmap/">newsmap</a> - which takes the news as aggregated by Google News, and builds a beautiful representation of what’s “hot” in the news.</p>
<h2>What I’ve done</h2>
<p>The work that I’ve been doing so far is pretty simple. I’ve taken the output of a single DTrace script (<code class="prettyprint">js_functime</code>, <a href="http://blogs.sun.com/brendan/entry/dtrace_meets_javascript">available on Brendan Gregg’s blog</a>) and used that to create a treemap. This DTrace script measures the time spent in Javascript functions. It’s not the most accurate measurement since the output is the overlapping times, but it’s still a good place to start. The output contains the number of times each function was called, the average time spent in the function, and the total time spent (across calls). From there I build these treemaps.</p>
<p>I’ve used a modified version of the <a href="http://rubytreemap.rubyforge.org/">RubyTreemap</a> gem to create SVG (Scalable Vector Graphics)s of this output. I create 3 different high-level maps, each representing the bits of information I get (count, average time, total time). Each of these maps is made from a tree 3 levels deep (though the root node is insignificant). The topmost level is the file from which the function is in. The second level is the function name. Size is determined from the measurement type (thus 3 maps). Each of these maps can then be broken down further, stepping into each individual file. So from these 3 “index” SVGs, I’ve linked down into the second level, and a new SVG is generated for each file, making it a bit easier to read the smaller nodes. Colors are consistent between runs and based on an adapted hashing algorithm.</p>
<p>I can’t hand out the source yet since the original RubyTreemap is GPL’ed and I’m not ready to redistribute. The changes aren’t huge, but are very focused for this task, so might not even be able to be merged back. Also, my code is pretty ugly right now and that would just lead to embarrassment.</p>
<p>So without further ado, here’s the page on playground: <em><a href="http://playground.zpao.com/dtrace_treemaps/">DTrace Treemaps</a></em>. Keep in mind that this is not complete and what you see may very well change soon. Here are the direct links to the SVGs if you are a bit impatient: <a href="http://playground.zpao.com/dtrace_treemaps/js_functime_count/index.svg">count</a>, <a href="http://playground.zpao.com/dtrace_treemaps/js_functime_avg/index.svg">average</a>, <a href="http://playground.zpao.com/dtrace_treemaps/js_functime_sum/index.svg">sum</a>.</p>
<h2>Future Directions</h2>
<p>From here I plan on using the output from some of the scripts in the <a href="http://opensolaris.org/os/community/dtrace/dtracetoolkit/">DTrace Toolkit</a> to create other visuals, likely more treemaps. I also need to do a number of things to package this nicely so it’s easy to adapt and use for different DTrace outputs. Last, but certainly not least, I need to make the code much better - it’s my own personal Frankenstein right now, and needs to suck less.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p><a href="http://en.wikipedia.org/wiki/DTrace">Wikipedia DTrace article</a>&nbsp;<a href="#fnref1" rev="footnote">&#8617;</a></p>
</li>
<li id="fn2">
<p><a href="http://en.wikipedia.org/wiki/Treemap">Wikipedia Treemapping article</a>&nbsp;<a href="#fnref2" rev="footnote">&#8617;</a></p>
</li>
</ol>
</div>
<img src="http://feeds.feedburner.com/~r/zpao/~4/Yb1rqs1PXH0" height="1" width="1" alt=""/>On Open Source2008-07-20T00:00:00-07:00https://zpao.com/posts/on-open-source<p>Two weeks ago, while working on a project yet to be revealed (unless you happen to stalk me on <a href="https://bugzilla.mozilla.org">Bugzilla</a> - I’ll write about it soon, I promise), I happened to make Minefield seg fault. I was talking to <a href="http://shawnwilsher.com/">Shawn Wilsher</a> about what I was working on, so he had some familiarity with the code, and told me it <em>shouldn’t</em> be crashing. But it was. Shawn told me to file a bug, create a test case, and get a stack trace with <a href="http://sourceware.org/gdb/">GDB</a>. I was a bit annoyed because it took time away from what I was working on. But I did all that, filed <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=444233">the bug</a>, and went along my way.</p>
<p>The other day, I got to work and found a few Bugzilla emails waiting. Apparently somebody had written a patch for the bug, and it had been r+ed and checked in. I figured somebody was looking at it, but a lot happened at once. So I took a look at the <a href="http://hg.mozilla.org/index.cgi/mozilla-central/rev/3c1f72eddf61">commit log</a> and it turns out that the test case I had written had been included! That makes perfect sense - we want to keep the test around to make sure we don’t regress in the future - but it still surprised me. I never came to Mozilla expecting to touch such a random place in the code base. And while I wasn’t fixing the C++ code, I was still contributing. It felt good.</p>
<p>I think <em>that</em> is part of the power of open source.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/UakrBz3hz24" height="1" width="1" alt=""/>Programming Brain Teaser2008-07-09T00:00:00-07:00https://zpao.com/posts/programming-brain-teaser<p>Since I was at a presentation during lunch, I took some time for myself and took a quick crack at Dustin Diaz’s <a href="http://www.dustindiaz.com/programming-brain-teaser/">programming brain teaser</a>. He said any language, so the quickest to get running for me is Ruby (and <code class="prettyprint">Command-R</code> in Textmate is so easy).</p>
<p>It’s not terribly clever, but it takes a different approach from some of the other solutions in that it modifies the array elements then just joins them, instead of creating a single output string and concatenating as time goes. My favorite solution in the comments used a regular expression, which I thought was particularly clever. Anyway, here’s mine:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># the array</span>
<span class="n">arr</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">,</span> <span class="s1">&#39;c&#39;</span><span class="p">,</span> <span class="s1">&#39;c&#39;</span><span class="p">,</span> <span class="s1">&#39;d&#39;</span><span class="p">,</span> <span class="s1">&#39;e&#39;</span><span class="p">,</span> <span class="s1">&#39;e&#39;</span><span class="p">,</span>
<span class="s1">&#39;e&#39;</span><span class="p">,</span> <span class="s1">&#39;e&#39;</span><span class="p">,</span> <span class="s1">&#39;e&#39;</span><span class="p">,</span> <span class="s1">&#39;f&#39;</span><span class="p">,</span> <span class="s1">&#39;e&#39;</span><span class="p">,</span> <span class="s1">&#39;f&#39;</span><span class="p">,</span> <span class="s1">&#39;e&#39;</span><span class="p">,</span>
<span class="s1">&#39;f&#39;</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;f&#39;</span><span class="p">,</span> <span class="s1">&#39;f&#39;</span><span class="p">,</span> <span class="s1">&#39;f&#39;</span><span class="o">]</span>
<span class="c1"># some variables</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">arr</span><span class="o">.</span><span class="n">each_index</span> <span class="k">do</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span>
<span class="c1"># not the same as previous letter, so do some things</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">!=</span> <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">]</span>
<span class="k">if</span> <span class="n">count</span> <span class="o">&gt;</span> <span class="mi">2</span>
<span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="o">]</span> <span class="o">+</span> <span class="s2">&quot;&quot;</span>
<span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">-</span><span class="n">count</span><span class="o">+</span><span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span> <span class="o">+</span> <span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">-</span><span class="n">count</span><span class="o">+</span><span class="mi">2</span><span class="o">]</span>
<span class="k">end</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">put_tag</span> <span class="o">=</span> <span class="kp">false</span>
<span class="k">end</span>
<span class="c1"># increment count</span>
<span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">end</span>
<span class="k">if</span> <span class="n">count</span> <span class="o">&gt;</span> <span class="mi">2</span>
<span class="n">arr</span><span class="o">[-</span><span class="mi">1</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[-</span><span class="mi">1</span><span class="o">]</span> <span class="o">+</span> <span class="s2">&quot;&quot;</span>
<span class="n">arr</span><span class="o">[-</span><span class="n">count</span><span class="o">+</span><span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span> <span class="o">+</span> <span class="n">arr</span><span class="o">[-</span><span class="n">count</span><span class="o">+</span><span class="mi">2</span><span class="o">]</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="n">arr</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">)</span>
</code></pre></div>
<p>Thinking back, I should have gone for some JavaScript, since that’s mostly what I’m writing these days. Oh well.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/zJRWzvicZzY" height="1" width="1" alt=""/>Introducing LOLcanvas2008-06-26T00:00:00-07:00https://zpao.com/posts/introducing-lolcanvas<p>Work has been going forward in (what will likely be) Firefox 3.1. While there are definitely changes happening in the front-end, there are also a number of changes happening in the backend (AKA Gecko 1.9.1) as well.</p>
<p>Gecko 1.9.1 is going to have even more improved CSS3 support, as <a href="http://dbaron.org/log/20080603-new-selectors">David Baron writes about</a>. He’s landed support for some additional CSS selectors. Rob Arnold has recently done work on <code class="prettyprint">border-image</code>, and I know at least one other intern is working on some CSS3 stuff.</p>
<p>More relevantly though, <a href="http://www.ericbutler.net/blog/2008/06/html-canvas-in-firefox-31/">Eric Butler</a> has done work on <code class="prettyprint">canvas</code> support. One thing that he’s worked on is getting the <code class="prettyprint">canvas</code> element text drawing up to speed, and more up to spec. I had some free time so I worked on a little demo to show off the new stuff.</p>
<p>It’s called <a href="http://playground.zpao.com/lolcanvas">LOLcanvas</a> and uses <code class="prettyprint">canvas</code> to draw text on a flickr image, client side. This is similar to another project I worked on before - <a href="http://flolcatr.com">flolcatr</a> - however now it’s all done right in the browser. Anyway, a picture is worth a thousand words, so here:</p>
<p><a href="http://www.flickr.com/photos/evapro/385650640/"><img src="http://zpao.com/images/lioncat.png" alt="omg surprize it&#39;s Lion cat" title="omg surprize it&#39;s Lion cat"></a></p>
<p>The details are on the <a href="http://playground.zpao.com/lolcanvas">LOLcanvas homepage</a>, so give it a try and have fun. If you have some additional phrases to add, let me know. I’ll be throwing the readable source up somewhere soon so that you can see exactly what’s happening.</p>
<p>Original image is <a href="http://creativecommons.org/licenses/by/2.0/deed.en">CC licensed</a> and <a href="http://www.flickr.com/photos/evapro/385650640/">available here</a>.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/8lFTCIQeiAk" height="1" width="1" alt=""/>It’s Awesome for a Reason2008-06-18T00:00:00-07:00https://zpao.com/posts/its-awesome-for-a-reason<p>Firefox 3 came out yesterday to much fanfare and <a href="http://www.spreadfirefox.com/en-US/worldrecord">a world record</a>. The world seems to like it, at least in general, though I have heard a bit of complaining. One thing in particular: the <a href="http://blog.mozilla.com/blog/2008/04/21/a-little-something-awesome-about-firefox-3/">Awesome Bar</a>.</p>
<p>This has been the number one complaint I’ve heard, and to be fair, I can’t blame people. When I first downloaded a beta (or maybe a nightly) back in January, I HATED the Awesome Bar. I spent a couple hours with it and bitched to Rob (who was and still is an intern). I just wanted URLs to be matched as they always had been, with the first few letters and then a bunch of arrow pressing as I chose the right page. By the end of those hours I was frustrated as all hell and wanted out. Rob told me about the <a href="https://addons.mozilla.org/en-US/firefox/addon/6227">oldbar</a> extension - which makes the Awesome Bar behave much like the old location bar - and installed it. I used Firefox &amp; Safari roughly equally over the next couple weeks, and then I interviewed with Mozilla.</p>
<p>During one of my interviews (with <a href="http://steelgryphon.com/blog/">Mike Connor</a> I believe), I was asked, “If you could change one thing about Firefox, what would it be?” I thought about it a second, and the first thing that came to mind was my new found hatred of the Awesome Bar, so I said that. I explained myself, and said some of the things that I said to Rob. My biggest gripe was that I just wanted URLs to be matched before titles of pages. Mike talked a bit about how it worked and how it used machine learning to adapt to how I used it. So if I just behaved like I used to and chose the page I was looking for, it would remember that for next time. He said it was still being tweaked and it wasn’t perfect yet, but that I really should give it another shot.</p>
<p>So I did, and since I knew a little bit more about it, I felt a little less apprehensive about using it. So I set out to “train” it. I bit the bullet and got some inaccurate results over the next week or two. At one point in there I opened my browser and could not for the life of me think of the domain or URL for a page I knew I had been to a couple days before. I did however know what the page was about (it was something specific about Java or some such nonsense for an assignment). So I just typed the topic into the Awesome Bar. Luckily the word I was thinking had been in the page title, and <del>viola</del> voil&agrave; - the first result after I had typed the word was the exact page I was looking for. It had proved itself to me. I probably would have spent another 20 minutes trying to remember exactly what I searched for on Google. I’ve been using it since and absolutely love it.</p>
<p>So just give it a shot and quit complaining. Yes, it is a complete paradigm shift. But it’s not called the Awesome Bar for nothing; it really is awesome once you give it a chance.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/osvDKngY3lY" height="1" width="1" alt=""/>My First Patch2008-06-12T00:00:00-07:00https://zpao.com/posts/my-first-patch<p>Today I put created my first patch for Firefox. It’s nothing major, but it still counts. It still hasn’t been r+ed yet (c’mon <a href="http://blog.mozilla.com/dolske/">dolske</a>!). Basically, it creates a public function that exposes a private function in the Password Manager. This makes it so that a user can have Firefox remember passwords, disable the feature to autofill login forms on page load, yet still expose the functionality to fill in the form. This opens it up for an extension to do that work.</p>
<p>I think Justin probably <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=359675#c26">said it better</a>:</p>
<blockquote>
<p>…it seems like a legitimate use case for those who want this as an option. At the very least by adding some flags to the existing code, so an extension could drive the UI side. [Eg, currently the password manager form-fill code can only be triggered by page loads, but it should be easy to expose this as an interface for extensions.]</p>
</blockquote>
<p>Better?</p>
<p>So if you’d like to read some more about it, there’s <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=359675">the discussion on Bugzilla</a> and <del><a href="https://bugzilla.mozilla.org/attachment.cgi?id=324865&amp;action=diff">the diff for the patch</a></del>. It’s not checked into source yet, but soon. So yea, this isn’t terribly exciting… unless you’re me.</p>
<p><strong>Update:</strong> The original patch got canceled since we decided it would be better to expose just the functionality to fill a form as opposed to the whole document, at least as a first step. There’s a <del><a href="https://bugzilla.mozilla.org/attachment.cgi?id=325053&amp;action=diff">new patch</a></del> in that’s now waiting for a review.</p>
<p><strong>Update 2:</strong> I was very preemptive here. I should have just waited until it actually got committed. I ended up getting r-ed a couple times, but it made it in. So without further ado, <a href="http://hg.mozilla.org/mozilla-central/index.cgi/rev/055a716092aa">the changeset.</a></p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/FLS4kvSIqDg" height="1" width="1" alt=""/>Interning at Mozilla: Week 12008-05-31T00:00:00-07:00https://zpao.com/posts/mozilla-week-1<p>I&rsquo;ve just finished my first week at Mozilla. So far it&rsquo;s been a blast. They&rsquo;ve put us up in a really nice temporary living apartment complex (<a href="http://www.oakwood.com/furnished-apartments/furnished/US/CA/Mountain-View/prop17/showPictures.html">pictures</a> and yes that <em>is</em> a 40 person hot tub), the other interns are all really nice, and well, it&rsquo;s California.</p>
<p>This week we had a poker game / movie night. I was in on poker and turned $10 into $30, which should keep from an ATM a little bit longer. They&rsquo;ve also been feeding us lunch this week; there&rsquo;s a stock of good snacks &amp; cereal, so I don&rsquo;t have to eat breakfast before work (although I have been).</p>
<p><strong>Anyway, on to Firefox.</strong></p>
<p>So I am on the Firefox team for the summer. My initial goals include working on profiling startup and improving shutdown. Neither of these are one day tasks, not even 1 week. In fact, both seem pretty lofty and fun to work on.</p>
<p>The improving shutdown part is where I&rsquo;ve been focusing first - it&rsquo;s something that has bothered me personally. The behavior is both inconsistent and can be pretty annoying. For example, if you close the last window vs. doing File|Exit (and have “Clear Privacy on Exit”) checked, you will have different outcomes when you try to restore your session. Not only that, but there are several different dialogs that can pop up. Then take into account leaving the Downloads window up when you close the last window — your session restore is screwed (at least last I remember). That is not the expected behavior.</p>
<p>So all this week I&rsquo;ve been digging through the Firefox source code with <a href="http://mxr.mozilla.org/mozilla-central/source/">MXR</a>. I haven&rsquo;t written a single line, just reading &amp; taking notes. It&rsquo;s not simple. Shutdown (or “Exit” or “Quit”) goes through a number of steps and then broadcasts a <code class="prettyprint">quit-application-requested</code> message. Other objects observe specific messages, so all the ones that observe <code class="prettyprint">quit-application-requested</code> are then triggered. Some of these in turn trigger dialogs, set preferences, close windows, and so on. Assuming all goes well there, <code class="prettyprint">quit-application-granted</code> and subsequently <code class="prettyprint">quit-application</code> are broadcast. These events can be triggered in either JavaScript or C++, not to mention that sometimes the JavaScript is being called from XUL, or XUL is “run” from Javascript. It&rsquo;s even more complicated than it may sound here, so maybe in a future post I&rsquo;ll break it down even more. I still haven&rsquo;t finished working it out completely. I&rsquo;ve looked at some of the “Close Window” code as well to track down where differences lie and how that can be made more consistent… All in all, it&rsquo;s hurts my brain a little bit.</p>
<p>That said, it&rsquo;s been a fun (albeit exasperating at times) week and I&rsquo;m looking forward to the rest of the summer.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/BJaOuZTcBJs" height="1" width="1" alt=""/>Reinstatement2008-05-14T00:00:00-07:00https://zpao.com/posts/reinstatement<p>I&rsquo;ve been absent from blogging for a while now. I know, you&rsquo;re all majorly disappointed. Anyway, I just wanted this to say that I&rsquo;m back and powered by my own little Rails app running on <a href="http://blog.dreamhost.com/2008/05/13/passenger-for-ruby-on-rails/">Passenger at Dreamhost</a></p>
<p>Blarg (this app) is really basic, uses <a href="http://haml.hamptoncatlin.com/">HAML</a>, <a href="http://github.com/matta/acts_as_taggable_on_steroids/tree/master">acts_as_taggable_on_steroids</a>, &amp; just some HTTP Auth… nothing fancy. Blarg is up on Github, but is private right now since it is very tailored for this site. I&rsquo;ll try to abstract it out a bit and then leave it open for the world to use.</p>
<p>Anyway, I&rsquo;m hoping to get back to blogging. I&rsquo;m going to try to make this a bit more professional than my last incarnation, but it will likely slip a bit into my personal life.</p>
<img src="http://feeds.feedburner.com/~r/zpao/~4/DehMCx1Gjn0" height="1" width="1" alt=""/>