<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Coffee on the Keyboard</title>
	<atom:link href="http://coffeeonthekeyboard.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://coffeeonthekeyboard.com</link>
	<description>by James Socol</description>
	<lastBuildDate>Mon, 08 Mar 2010 17:01:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Code-sharing Update</title>
		<link>http://coffeeonthekeyboard.com/code-sharing-update-361/</link>
		<comments>http://coffeeonthekeyboard.com/code-sharing-update-361/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 17:01:10 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[amo]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[sumo]]></category>
		<category><![CDATA[team]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=361</guid>
		<description><![CDATA[When we decided to move SUMO to a new platform, one of the reasons we chose Django was code sharing and reuse—specifically that SUMO and AMO would be able to share code, meaning both teams would save time and see benefits.
So how is that going? Were we right in our assumption here? The code we&#8217;re [...]]]></description>
			<content:encoded><![CDATA[<p>When we decided to <a href="http://coffeeonthekeyboard.com/the-evolution-of-sumo-339/">move SUMO to a new platform</a>, one of the reasons we chose <a href="http://www.djangoproject.com/">Django</a> was code sharing and reuse—specifically that <a href="http://support.mozilla.com/">SUMO</a> and <a href="https://addons.mozilla.org">AMO</a> would be able to share code, meaning both teams would save time and see benefits.</p>
<p>So how is that going? Were we right in our assumption here? The code we&#8217;re sharing so far:</p>
<dl>
<dt><a href="http://github.com/jbalogh/django-multidb-router">MultiDB Router</a></dt>
<dd>A Django DB router that supports reading from a pool of slave databases.</dd>
<dt><a href="http://github.com/jbalogh/django-cache-machine">Cache Machine</a></dt>
<dd>A powerful caching library for Django that, in particular, provides automatic object caching and invalidation through the ORM.</dd>
<dt><a href="http://github.com/jbalogh/jingo">Jingo</a></dt>
<dd>An adapter for using <a href="http://jinja.pocoo.org/2/">Jinja2</a> templates with Django.</dd>
<dt><a href="http://github.com/jbalogh/django-nose">Django-Nose</a></dt>
<dd>A test runner for Django using <a href="http://somethingaboutorange.com/mrl/projects/nose/0.11.2/">Nose</a>.</dd>
<dt><a href="http://github.com/jbalogh/django-debug-cache-panel">Django Debug Cache Panel</a></dt>
<dd>Adds a cache panel for <a href="http://github.com/robhudson/django-debug-toolbar">Django Debug Toolbar</a>.</dd>
<dt><a href="http://github.com/jbalogh/test-utils">Test-Utils</a></dt>
<dd>Tools we use testing in the Django/Jinja2/Nose setup.</dd>
<dt><a href="http://github.com/jsocol/bleach">Bleach</a></dt>
<dd>A library for sanitizing and linkifying user HTML, based on <a href="http://code.google.com/p/html5lib/">html5lib</a>.</dd>
<dt><a href="http://github.com/davedash/django-fixture-magic">Fixture Magic</a></dt>
<dd>Django management commands for working with fixture data.</dd>
</dl>
<p>Additionally, we expect both teams will probably use the following, eventually:</p>
<dl>
<dt><a href="http://github.com/jsocol/didyoumean">DidYouMean</a></dt>
<dd>A wrapper for <a href="http://hunspell.sourceforge.net/">Hunspell</a>, using <a href="http://code.google.com/p/pyhunspell/">PyHunspell</a> to provide spelling suggestions for searches.</dd>
<dt><a href="http://github.com/fwenzel/django-gearman">Django Gearman</a></dt>
<dd>Provides an easier interface from Django to the Python <a href="http://gearman.org/">Gearman</a> bindings.</dd>
<dt>AMO&#8217;s JS and CSS minification</dt>
<dd>AMO has already solved the problem of JS and CSS minification with Django and Jinja2.</dd>
</dl>
<p>And it&#8217;s not a released library, but SUMO has also been able to directly reuse code from AMO to simplify pagination.</p>
<p>Overall, it seems like we&#8217;re doing really well on this! It&#8217;s great to see the projects not just sharing code, but packaging and publishing it on Github and <a href="http://pypi.python.org/pypi">PyPI</a>. If any of the above is useful to you, go ahead and try it out! You can open issues with any of the packages on Github, or find us in <a href="irc://irc.mozilla.org/webdev">#webdev</a> in irc.mozilla.org.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/code-sharing-update-361/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bleach, HTML sanitizer and auto-linker</title>
		<link>http://coffeeonthekeyboard.com/bleach-html-sanitizer-and-auto-linker-for-django-344/</link>
		<comments>http://coffeeonthekeyboard.com/bleach-html-sanitizer-and-auto-linker-for-django-344/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 19:22:00 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[sanitize]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[user]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=344</guid>
		<description><![CDATA[Bleach is a whitelist-based HTML sanitizer and auto-linker in Python, built on html5lib, for AMO and SUMO and released under the BSD license.
Bleach has two main functions: sanitizing HTML based on a whitelist of tags and attributes, and turning URLs into links. It uses html5lib for both.
For more information on using Bleach, see the README [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/jsocol/bleach">Bleach</a> is a whitelist-based HTML sanitizer and auto-linker in Python, built on <a href="http://code.google.com/p/html5lib/">html5lib</a>, for <a href="https://addons.mozilla.org/">AMO</a> and <a href="http://support.mozilla.com/">SUMO</a> and released under the BSD license.</p>
<p>Bleach has two main functions: sanitizing HTML based on a whitelist of tags and attributes, and turning URLs into links. It uses html5lib for both.</p>
<p>For more information on using Bleach, see the <a href="http://github.com/jsocol/bleach/blob/master/README.rst">README</a> included in the source. For more info on how Bleach works, follow below the jump.<span id="more-344"></span></p>
<h3>Sanitizing HTML</h3>
<p>Bleach&#8217;s <code>clean()</code> function uses a slightly custom version of html5lib&#8217;s <code>HTMLSanitizer</code> tokenizer that adds support for per-tag attribute whitelists. Any entity that is not part of a whitelisted tag or valid entity will be encoded. Legitimate entities and tags are allowed. The default whitelist is set up for AMO.</p>
<h3>Linkifying Text</h3>
<p>The <code>linkify()</code> function is a little more complicated. Naïve implementations usually rely on a simple regular expression to find URL-like strings, but this quickly becomes insufficient when you need to handle situations like these:</p>
<ul>
<li><code>&lt;em&gt;http://example.com&lt;/em&gt;</code> (should be linkified)</li>
<li><code>&lt;a href="http://example.com"&gt;test&lt;/a&gt;</code> (already linked, no need to linkify)</li>
<li><code>&lt;a href="http://example.com"&gt;http://example.com&lt;/a&gt;</code> (really don&#8217;t need to linkify)</li>
<li><code>&lt;em&gt;http://xx.com &lt;a href="http://example.com"&gt;http://example.com&lt;/a&gt;&lt;/em&gt;</code> (regular expression freak-out)</li>
</ul>
<p>So <code>linkify()</code> actually uses html5lib to build a document fragment and walks it, only applying the naïve regular expression in safe locations. In pseudocode:</p>
<div class="dean_ch" style="white-space: wrap;">tree = parseFragment<span class="br0">&#40;</span><span class="kw2">input</span><span class="br0">&#41;</span></p>
<p>linkify_nodes <span class="br0">&#40;</span>tree<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">for</span> node <span class="kw1">in</span> tree:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> node <span class="kw1">is</span> a text node:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; replace node with text nodes <span class="kw1">and</span> links<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="kw1">if</span> node <span class="kw1">is</span> a link:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> nofollow:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">set</span> rel=<span class="st0">&quot;nofollow&quot;</span> on node<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; linkify_nodes<span class="br0">&#40;</span>node.<span class="me1">childNodes</span><span class="br0">&#41;</span></p>
<p><span class="kw1">return</span> <span class="kw3">string</span><span class="br0">&#40;</span>linkify_nodes<span class="br0">&#40;</span>tree<span class="br0">&#41;</span><span class="br0">&#41;</span></div>
<p>This avoids attempting to apply the regular expression to things like tag attributes, the inside of <code>&lt;a&gt;</code> tags, and other places it should generally be avoided. It also lets us do things like set the <code>rel</code> attribute on links already in the text and pass the <code>href</code> attribute through the same filter it would go through if we created the link. This filter lets us redirect links through an outbound redirect, so people know they&#8217;re leaving a Mozilla site. You could do other things with it, like rickroll your visitors. That&#8217;s up to you.</p>
<h3>Bad HTML</h3>
<p>Because both <code>clean()</code> and <code>linkify()</code> use <code>html5lib</code> and construct document trees, using either will fix up code mistakes, like unclosed takes, and escape bare entities. <code>linkify()</code> allows basically every tag and attribute, so if you need to limit the legal HTML to a subset, use <code>clean()</code> (or the shortcut <code>bleach()</code> to clean then linkify).</p>
<h3>Getting Bleach</h3>
<p>Bleach is <a href="http://github.com/jsocol/bleach">available on Github</a>, or can be installed via <code>pip</code> or <code>easy_install</code>. Improvements and test cases are very welcome! Actually, there&#8217;s one disabled test right now that is not supported. If you can make it work, that would be pretty great!</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/bleach-html-sanitizer-and-auto-linker-for-django-344/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Evolution of SUMO</title>
		<link>http://coffeeonthekeyboard.com/the-evolution-of-sumo-339/</link>
		<comments>http://coffeeonthekeyboard.com/the-evolution-of-sumo-339/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 22:39:21 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[sumo]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=339</guid>
		<description><![CDATA[When I joined the SUMO team six months ago, the team was just starting a discussion of &#8220;where do we go from here?&#8221;  SUMO was built on a CMS called TikiWiki, and had diverged pretty significantly in two years. (David Tenser wrote a more detailed history if you&#8217;re interested.)
After a few months of talking and [...]]]></description>
			<content:encoded><![CDATA[<p>When I joined the <a title="SUpport dot MOzilla dot com" href="http://support.mozilla.com/" target="_blank">SUMO</a> team six months ago, the team was just starting a discussion of &#8220;where do we go from here?&#8221;  SUMO was built on a <abbr title="Content Management System">CMS</abbr> called <a href="http://tikiwiki.org/" target="_blank">TikiWiki</a>, and had diverged pretty significantly in two years. (David Tenser wrote <a href="http://blog.mozilla.com/sumo/2010/02/18/the-bright-future-of-the-sumo-platform/" target="_blank">a more detailed history</a> if you&#8217;re interested.)</p>
<p>After a few months of talking and testing—and a few changes of direction—we&#8217;ve decided that SUMO will follow our colleagues on <a title="Addons dot Mozilla dor Org" href="https://addons.mozilla.org/" target="_blank">AMO</a> and move to a custom web application, built on <a href="http://www.djangoproject.com/">Django</a>, a development framework in Python.</p>
<p>Why are we committing to such a dramatic new direction? Three major reasons. <span id="more-339"></span><em>Keep in mind that SUMO was built on TikiWiki 1.10, a little more than two years out of date.</em></p>
<h3>Performance</h3>
<p>TikiWiki is a very feature-rich application. An unfortunate trade-off for us is performance, especially on a site serving 16 million users every week. <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=532498" target="_blank">As our European users</a> in particular know, SUMO can be unacceptably slow at times, especially when editing articles. Many of the changes we made to the platform—most of which were contributed back over the past few months—were to improve performance via tools like output caching, database replication, and just refactoring. When we evaluated the latest version of TikiWiki, we found that performance was around the same, on average.</p>
<p>In the new platform, we&#8217;ll be taking advantage of techniques now available, including query and template/fragment caching and expect to see dramatic performance improvements. We&#8217;ll also be avoiding some of the performance pitfalls that TikiWiki fell into over the years with improvements to the security, database, and templating layers, among others.</p>
<p>But the biggest performance impact—I expect—will be moving from a general-purpose CMS to a dedicated web application, focused on providing the SUMO experience.</p>
<h3>Hackability</h3>
<p>To work on SUMO, you have to overcome a steep learning curve. Components tend to be tightly-coupled, or grouped in unintuitive ways, and are not as extensible as we&#8217;d like. The lack of a comprehensive test suite leaves changes to important sections of code open to introducing regressions in otherwise unrelated, dependent areas. SUMO 1.x also fails to function without a relatively complete copy of its database, which makes it difficult for community members outside the company to contribute.</p>
<p>With the new platform, and some discipline from the team, our goal is to improve all of these and make it easier for someone to get started hacking on SUMO.</p>
<ul>
<li>We&#8217;ll be striving to keep code loosely-coupled and extensible—including using existing or external libraries whenever possible, and turning our own contributions into external libraries where possible.</li>
<li>We&#8217;re adopting a test-driven development workflow to ensure that our components are easier to safely hack, and lighten the load on our <abbr title="Quality Assurance">QA</abbr> team by reducing regressions.</li>
<li><abbr title="Test-Driven Development">TDD</abbr> and Django will make it easier to work without a copy of the database, using fixtures and migrations to minimize the dependence on real data.</li>
</ul>
<p>The net effect of these decisions will be to lower the barrier to entry to SUMO development, and hopefully make useful code available to other projects. Wil Clouser <a href="http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/" target="_blank">listed more strengths</a> of Django as a platform when the AMO team decided to switch.</p>
<h3>Strength in Numbers</h3>
<p>By using the same platform as AMO, both teams will benefit from sharing code and resources. We&#8217;re already using the same template adapter, database router, caching layer, and HTML sanitizer. As open source developers often say: &#8220;with enough eyes, all bugs are shallow,&#8221; and by sharing code we get more eyes on it. We&#8217;ll benefit from insights the AMO team has gleaned by starting the process of moving from a PHP framework to Python just ahead of us. We&#8217;ll even be able to send code reviews across teams and benefit from deeper knowledge of the various problem domains we share: have a question about localization? Both teams can share expertise and best-practices.</p>
<p>Solving problems once and sharing the solution directly reduces the amount of work both teams have to do. And when SUMO writes code in such a way that AMO can use it, we can also release it separately so others can benefit from our solutions—and point out flaws and contribute improvements.</p>
<h3>Other Changes</h3>
<p>Also among the changes coming in the next year:</p>
<ul>
<li><strong>Version Control System. </strong>Though we don&#8217;t have a specific plan in place, it seems likely that SUMO will be moving from SVN to Git for source control. Because Git is distributed, it allows us to use a more <a href="http://nvie.com/archives/323" target="_blank">collaborative workflow</a>, and it&#8217;s easier for us to push our code to public repositories like <a href="http://github.com/">Github</a>.</li>
<li><strong>Continuous Integration.</strong> We&#8217;ll be using <a href="https://hudson.dev.java.net/">Hudson</a> for continuous integration, which will automate our tests and alert us to potential issues and regressions. The web QA team has also been working to make sure our <a href="http://seleniumhq.org/">Selenium</a> tests can run through Hudson, greatly increasing test coverage for a web application like SUMO.</li>
<li><strong>Interface Localization</strong>. One of the ways we plan to improve the SUMO experience this year is by moving our interface localization to <a href="http://www.gnu.org/software/gettext/">gettext</a>, which is an industry-standard tool for localization. As we move parts of the site from TikiWiki to Django, those new sections will be localized via gettext, which helps us take advantage of our great community with tools like <a href="http://localize.mozilla.org/">Verbatim</a>.</li>
</ul>
<h3>A Foundation for the Future</h3>
<p>The goal of all of this work—and it will be a lot of work—is to put SUMO on a solid foundation for future growth and, at the same time, improve the experience for everyone—from developers to contributors to localizers to visitors. We have a daunting and aggressive road ahead of us, but I&#8217;m confident that we&#8217;ll emerge in a better place.</p>
<p>SUMO 2 is codenamed <a href="https://wiki.mozilla.org/Support/Kitsune">Kitsune</a>, and is already <a href="http://github.com/jsocol/kitsune">up on Github</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/the-evolution-of-sumo-339/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>How to Install VirtualBox Guest Additions in Fedora 12</title>
		<link>http://coffeeonthekeyboard.com/how-to-install-virtualbox-guest-additions-in-fedora-12-332/</link>
		<comments>http://coffeeonthekeyboard.com/how-to-install-virtualbox-guest-additions-in-fedora-12-332/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 08:43:42 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[vbox]]></category>
		<category><![CDATA[vm]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=332</guid>
		<description><![CDATA[Update: Whoa! Looks like my instructions only work for 64-bit guests. Scroll down to the bottom for the changes you need to make for a 32-bit Fedora guest.
This was not quite as straightforward as I remember it being in Fedora 11. I ran into a problem and couldn&#8217;t find the solution in 5 minutes of [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update:</strong> Whoa! Looks like my instructions only work for 64-bit guests. Scroll down to the bottom for the changes you need to make for a 32-bit Fedora guest.</p>
<p>This was not quite as straightforward as I remember it being in Fedora 11. I ran into a problem and couldn&#8217;t find the solution in 5 minutes of searching, so I offer it here: the steps to install VBox Guest Additions in Fedora 12.</p>
<p>I&#8217;m assuming you&#8217;re using VBox 3.1.2 (latest as of writing) and the kernel version is 2.6.31.9 on an x86_64. What does all that mean? In the long strings of numbers, some of them might change for you.</p>
<p>First, in the VM menu (not the Guest but the chrome around it) go to <strong>Devices &gt; Install Guest Additions</strong>. It will mount a new disc image. Then fire up terminal.</p>
<pre><code>$ su
# yum install kernel-headers kernel-devel gcc
# export KERN_DIR=/usr/src/kernels/2.6.31.9-174.fc12.x86_64
# cd /media/VBOXADDITIONS_3.1.2_56127
# ./VBoxLinuxAdditions-amd64.run</code></pre>
<p>This time the kernel modules should compile. Then restart the system.</p>
<h3>Caveats!</h3>
<p>There&#8217;s a pretty good chance that some directories will be different, so rather than typing this out, you probably want to make liberal use of the <kbd>tab</kbd> key. Navigate to the right source directory (probably the only one in <code>/usr/src/kernels</code>) and then try: <code># export KERN_DIR=`pwd`</code></p>
<p>There&#8217;s also a small chance you might get an error that says <code>gksu: not found</code>, and most probably the autorun script won&#8217;t do anything. I ran <code># ln -s /usr/bin/sudo /bin/gksu</code> and it seemed to clear the problem up. (I only ran into this when starting the install via <code>autorun.sh</code>, not with the <code>.run</code> file.</p>
<h3>Update for 32-bit Guests</h3>
<p>A few possible changes if this doesn&#8217;t work for you with a 32-bit guest. (It didn&#8217;t for me, so I had to play around/research a bit more.)</p>
<ol>
<li>Run <code># uname -r</code>. If you see the letters <code>PAE</code>, then you&#8217;ll need to follow the rest of these steps. If you <em>don&#8217;t</em> see <code>PAE</code>, you should be fine.</li>
<li>If so, make sure your kernel is up to date with <code># yum update kernel-PAE</code>. After this, restart.</li>
<li>Instead of the <code>kernel-devel</code> package, you&#8217;ll need to install <code>kernel-PAE-devel</code>. That makes the second line of the example above:<br />
<code># yum install kernel-headers kernel-PAE-devel gcc</code></li>
<li>If you&#8217;d already installed the <code>kernel-devel</code> package, you may want to remove it: <code># yum remove kernel-devel</code> as it can confuse things.</li>
<li>Then, everything else should be the same.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/how-to-install-virtualbox-guest-additions-in-fedora-12-332/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Local Web Development</title>
		<link>http://coffeeonthekeyboard.com/local-web-development-323/</link>
		<comments>http://coffeeonthekeyboard.com/local-web-development-323/#comments</comments>
		<pubDate>Tue, 08 Dec 2009 23:14:30 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[vm]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=323</guid>
		<description><![CDATA[I&#8217;m not ashamed of it: I like Windows. I think the user experience is light-years ahead of Gnome and KDE. There&#8217;s nothing ostensibly wrong with OS X, but there are little usability differences and frankly switching isn&#8217;t worth the annoyance to me. That&#8217;s why I run Windows 7 on all three computers I use daily.
This [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m not ashamed of it: I like Windows. I think the user experience is light-years ahead of Gnome and KDE. There&#8217;s nothing ostensibly <em>wrong</em> with OS X, but there are little usability differences and frankly switching isn&#8217;t worth the annoyance to me. That&#8217;s why I run Windows 7 on all three computers I use daily.</p>
<p>This is only a problem when I try to work on LAMP web applications. Sure, I could install <a href="http://www.apachefriends.org/en/xampp.html">XAMPP</a>, but running Apache/PHP on Windows is really not close enough to a production environment. So I have two choices: I can dual-boot Linux and work in an OS—well, a window manager—I don&#8217;t like, or I can turn to virtual machines.<span id="more-323"></span></p>
<p><a href="http://www.vmware.com/">VMWare</a> is a pretty heavyweight solution. <a href="http://www.vmware.com/products/fusion/">Fusion</a>, for OS X, is a great product. But in Windows, I opt for Sun&#8217;s <a href="http://www.virtualbox.org/">VirtualBox</a>.</p>
<div id="attachment_324" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-324" title="virtualbox-new" src="http://coffeeonthekeyboard.com/wp-content/uploads/2009/12/virtualbox-new-300x206.png" alt="VirtualBox New Virtual Machine Wizard" width="300" height="206" /><p class="wp-caption-text">VirtualBox New Virtual Machine Wizard</p></div>
<p>VirtualBox lets me run Linux (I opt for <a href="http://fedoraproject.org/get-fedora">Fedora</a> as it&#8217;s close to our production environment and I like it) in just another window, right next to Firefox.</p>
<p>To create a new <abbr title="Virtual Machine">VM</abbr>, you&#8217;ll only need VirtualBox and a Linux ISO. (Or, you could use a pre-existing VM, or an &#8220;appliance,&#8221; copied from somewhere else. I&#8217;m not going to cover that.) Step through the wizard. Some of my recommended settings:</p>
<div id="attachment_325" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-325" title="virtualbox-disk" src="http://coffeeonthekeyboard.com/wp-content/uploads/2009/12/virtualbox-disk-300x268.png" alt="VirtualBox New Disk Settings" width="300" height="268" /><p class="wp-caption-text">VirtualBox New Disk Settings</p></div>
<ul>
<li>At least 512 MB of RAM for running Gnome+Apache+MySQL+VIm(+Firef0x?) in the VM.</li>
<li>At least 30 GB of hard disk. Yes, you can add more later, but expanding an existing disk is difficult, and if you use a &#8220;Dynamically expanding storage&#8221;-type of disk (see above) it won&#8217;t take the full 30 GB right off the bat.</li>
<li>There are two ways to go about doing Network settings—I do both.
<ul>
<li>Use Bridged networking. This gives your VM an IP address accessible to the rest of your network.</li>
<li>Use NAT. This gives your VM an IP address on a virtual network that only exists in your computer, but with a virtual gateway giving your VM access to the internet.</li>
<li>(You can also use Host-only networking, but that would prevent your VM from accessing the internet at all, and that&#8217;s no good.)</li>
</ul>
</li>
<li>Mount your installation media ISO as a CD/DVD drive via VirtualBox. You&#8217;ll be able to boot off the ISO and install Linux. You may run into issues if you leave the ISO mounted after installation.</li>
</ul>
<div id="attachment_326" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-326" title="virtualbox-network" src="http://coffeeonthekeyboard.com/wp-content/uploads/2009/12/virtualbox-network-300x260.png" alt="VirtualBox Network Settings" width="300" height="260" /><p class="wp-caption-text">VirtualBox Network Settings</p></div>
<p>Once you&#8217;re in Linux, set up your web server environment (use yum, apt-get, or whatever other package manager you choose). The key software I use:</p>
<ul>
<li>Apache</li>
<li>PHP</li>
<li>MySQL</li>
<li>Memcached</li>
<li>Sphinx</li>
<li>Squid</li>
</ul>
<p>With the software above, I can very nearly replicate the production environment for our web applications, while still spending most of my time in Windows. (When I do switch to the VM, I&#8217;m usually in VIm, my favorite text editor, anyway.)</p>
<p>Apache/PHP/MySQL is the typical PHP app stack. We use memcached for output caching (on <a href="http://support.mozilla.com/">SUMO</a>, anyway). We use Sphinx to power our search engine. Squid is useful from time to time for approximating an application behind a reverse-proxy cache and load-balancing server. (You could also use nginx or Varnish.)</p>
<p>If you use NAT or Bridged networking, you&#8217;ll be able to navigate to your VM&#8217;s IP address from a browser on the host computer (in my case, in Windows). By using Bridged, I can access my local Apache instance from browsers on Windows, Linux, or a nearby Mac, which is immensely valuable when doing browser support work and testing. I can even send my VM&#8217;s IP address to other people in the office and have them look at my local work.</p>
<p>There is a performance cost with a VM. HTTP requests would come back faster in a real Linux environment, and sometimes I do boot into Linux, but the convenience is worth it to me.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/local-web-development-323/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>So You Wanna Help Mozilla?</title>
		<link>http://coffeeonthekeyboard.com/so-you-wanna-help-mozilla-316/</link>
		<comments>http://coffeeonthekeyboard.com/so-you-wanna-help-mozilla-316/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 00:45:22 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[amo]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[sumo]]></category>
		<category><![CDATA[support]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[web dev]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=316</guid>
		<description><![CDATA[A common theme we heard in responses to our web developer survey was: &#8220;I wish I could help Mozilla, but I&#8217;m just a web developer.&#8221;
Well, fellow web ninjas, you can put your skills to work with Mozilla and help make the web a better place. Our web projects are open, just like Firefox, and we&#8217;d [...]]]></description>
			<content:encoded><![CDATA[<p>A common theme we heard in responses to our <a href="http://hacks.mozilla.org/2009/11/web-developer-survey-update/">web developer survey</a> was: &#8220;I wish I could help Mozilla, but I&#8217;m just a web developer.&#8221;</p>
<p>Well, fellow web ninjas, you <em>can</em> put your skills to work with Mozilla and help make the web a better place. Our web projects are open, just like Firefox, and we&#8217;d love your help!</p>
<p>If you&#8217;re a web developer and want to help Mozilla and Firefox users while working on sites that see millions of visitors every day, follow me through the jump and I&#8217;ll show you around our shop and introduce you to the tools we use.<span id="more-316"></span></p>
<h3>Our Projects</h3>
<p>Mozilla Web Dev is responsible for pretty much every web site at Mozilla, from <a href="https://addons.mozilla.org/">Addons</a> to <a href="http://support.mozilla.com/">Support</a> to <a href="http://www.mozilla.com/">Mozilla.com</a> to <a href="http://www.spreadfirefox.com/">Spread Firefox</a>. We also take care of web services like the <a href="https://wiki.mozilla.org/AUS">Application Update Service</a>, <a href="https://wiki.mozilla.org/PFS2">Plugin Finder Service</a> and the <a href="https://wiki.mozilla.org/Socorro">Crash Report Beacon</a>.</p>
<p>Almost all of our code (everything except Socorro—the crash report beacon—I think) is available on <a href="http://viewvc.svn.mozilla.org/vc/">svn.mozilla.org</a>. You can browse around the server and see the source right now. It will all basically run on the standard LAMP (where P is PHP or Python) stack.</p>
<h3>Our Tools</h3>
<p>The control center of web development at Mozilla is <a href="http://bugzilla.mozilla.org/">Bugzilla</a>. All our work takes the form of &#8220;bugs&#8221; here. A &#8220;bug&#8221; is not necessarily a problem with the software. A new feature or a software update would also be called a &#8220;bug.&#8221; I&#8217;ll talk about the life-cycle of a web development bug below.</p>
<p>IRC is just as important as Bugzilla. Both our staff and our contributors are geographically diverse, and IRC gives us a good way to coordinate and talk to each other around the globe. If you&#8217;re new to IRC, <a href="https://addons.mozilla.org/en-US/firefox/addon/16">ChatZilla</a> is an easy place to start. Most projects have their own channel on <a href="http://irc.mozilla.org/">irc.mozilla.org</a>, like <a href="irc://irc.mozilla.org/sumo">#sumo</a> for Support and <a href="irc://irc.mozilla.org/amo">#amo</a> for Addons. We&#8217;re also usually in <a href="irc://irc.mozilla.org/webdev">#webdev</a>.</p>
<p>As web developers, are chief weapon is HTML. HTML and CSS. HTML, CSS, and JavaScript. <em>No one expects the&#8230;</em> (Sorry.) On the front-end, we chiefly work in HTML, CSS, and JavaScript, and occasionally other technologies like XML. On the back-end, nearly all of our projects are in PHP or Python.</p>
<p>For version control we mostly use Subversion, though git (and git-svn) has gained a bunch of ground lately. (Addons will be <a href="http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/">moving to git</a> sometime next year.)</p>
<p>To work on your own computer, you&#8217;ll probably need to set up Apache, MySQL, and PHP or Python. <a href="http://www.apachefriends.org/en/xampp.html">XAMPP</a> can be incredibly helpful here. Working on Linux (or Mac OS) is usually easier than Windows, and closer to our server environment. A tool like <a href="http://www.virtualbox.org/">VirtualBox</a> will let you run a Linux virtual machine on most other operating systems. It&#8217;s a little slower but switching back and forth is easy. I&#8217;ll try to write about my local development set up soon.</p>
<h3>Our Workflow</h3>
<p>Let&#8217;s go over the life of a bug. This is a little long-winded.</p>
<p>A bug is born either when someone describes a problem or when we decide to add a new feature. (Every project has its own way of doing the latter.) Sometimes our Web <abbr title="Quality Assurance">QA</abbr> team finds problems, sometimes community members do. Then the bug is created, or filed, usually by the person who discovers it—that could be you!</p>
<p>Once a bug has been filed, possibly after some discussion of the best way to fix it, a developer—and that could be you, too—will &#8220;take&#8221; the bug, accepting responsibility for fixing it. Fixing a bug means changing the application in some way: changing a behavior, adding a localization, etc.</p>
<p>When the developer believes they&#8217;ve fixed the problem in their copy, they generate a patch (Subversion&#8217;s &#8220;diff&#8221; command is useful). They then upload that patch as a new attachment, and request review (r?) from someone else. Who does the review will depend on the project and how busy everyone is. If you&#8217;re not sure who to ask, ask in IRC.</p>
<p>The patch will either get an r+ or an r-. An r+ means it&#8217;s good to go, and it can usually be checked in to Subversion (unless there are reasons to wait). An r- means there&#8217;s something wrong. This can range from a patch containing some extraneous data to a patch not solving the problem, and an r- almost always includes a description of the problem.</p>
<p>When a patch with a positive review (r+) gets checked in to Subversion, the developer will include the revision in the bug and change it from <em>new</em> to <em>resolved: fixed</em>. In a few minutes, the change will appear on a staging server that&#8217;s updated frequently with the latest code. Our Web QA staff and contributors will test the bug, compare expected to actual behavior, and with either <em>reopen</em> the bug, if it&#8217;s not fixed, or set the status to <em>verified</em>. Then the bug is considered done. Verified bugs rarely reopen.</p>
<p>Once all the bugs for a milestone are done, we &#8220;freeze&#8221; the source against new commits while Web QA does a final check that everything is in good shape. When QA signs off on the current code, we push the new version onto our production web servers.</p>
<p>So that&#8217;s the life of a bug, from filed to production. When it gets to production, your code can be seen or used by millions of people every day.</p>
<h3>Join Us</h3>
<p>So if you&#8217;re a web developer and want to help Mozilla and Firefox, head over to Bugzilla or IRC and get started. We hope to see you soon!</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/so-you-wanna-help-mozilla-316/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Mistakes: Importing Data with MySQL</title>
		<link>http://coffeeonthekeyboard.com/mistakes-importing-data-with-mysql-309/</link>
		<comments>http://coffeeonthekeyboard.com/mistakes-importing-data-with-mysql-309/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 01:53:00 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[cli]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[learn from me]]></category>
		<category><![CDATA[mistake]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[pipe viewer]]></category>
		<category><![CDATA[pv]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=309</guid>
		<description><![CDATA[I blew most of the day trying to load data into MySQL because I didn't read. Hopefully my trials with 'max_allowed_packet' will help you avoid the same fate.]]></description>
			<content:encoded><![CDATA[<p>I spent the better part of today trying to import—in various attempts—between 800 MB and 3.1 GB of data into a local MySQL server. The whole time I was Doing It Wrong™. Now I feel like <a href="http://www.flickr.com/photos/zachklein/54389823/">this</a>:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-310" title="Image by Zach Klein" src="http://coffeeonthekeyboard.com/wp-content/uploads/2009/11/frustrated.jpg" alt="frustrated" width="240" height="160" /></p>
<p>I was using <a href="http://spindrop.us/2009/09/16/getting-started-with-pipe-viewer/">pipe viewer</a>, which obscured the error for most of the day. (If there&#8217;s a way to stop <code>pv</code> from eating messages to stderr, please let me know!) But eventually I figured out it was hitting the <code>max_allowed_packet</code> limit and my import was dying. I was using the MySQL docs as my reference point, and <a href="http://dev.mysql.com/doc/refman/5.0/en/using-system-variables.html">they imply</a> that the following should work:</p>
<pre>$ mysql --max_allowed_packet=32M db &lt; data.sql</pre>
<p>I know now that this does not work. And I feel like a moron. If you read carefully, which I did not, you&#8217;ll see that they&#8217;re talking about server startup, not client startup, even though the example uses &#8220;mysql&#8221; instead of &#8220;mysqld&#8221;.</p>
<p>When I stopped using pipe viewer, I got this series of errors:</p>
<pre>$ mysql --max_allowed_packet=16M db &lt; data.sql
ERROR 1153 (08501) at line 175458: Got a packet \
    bigger than 'max_allowed_packet' bytes
$ mysql --max_allowed_packet=128M db &lt; data.sql
ERROR 1153 (08501) at line 175458: Got a packet \
    bigger than 'max_allowed_packet' bytes
$ mysql --max_allowed_packet=256M db &lt; data.sql
ERROR 1153 (08501) at line 175458: Got a packet \
    bigger than 'max_allowed_packet' bytes
$ mysql --max_allowed_packet=1G db &lt; data.sql
ERROR 1153 (08501) at line 175458: Got a packet \
    bigger than 'max_allowed_packet' bytes</pre>
<p>Now here&#8217;s the thing, data.sql was just shy of 80 MB. So obviously something was wrong.</p>
<p>A quick edit to <code>/etc/my.cnf</code>:</p>
<pre>[mysqld]
...
max_allowed_packet=32M
...</pre>
<p>Then all I had to do was restart mysqld, and the next time I tried:</p>
<pre>mysql db &lt; data.sql</pre>
<p>It finished without a problem.</p>
<p>7 hours and a massive facepalm later&#8230; I hope this keeps someone from wasting the same amount of time I did on such a dumb mistake.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/mistakes-importing-data-with-mysql-309/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Getting Involved with Mozilla Web Dev</title>
		<link>http://coffeeonthekeyboard.com/getting-involved-with-mozilla-web-dev-306/</link>
		<comments>http://coffeeonthekeyboard.com/getting-involved-with-mozilla-web-dev-306/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 21:09:53 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=306</guid>
		<description><![CDATA[We&#8217;ve got a new page on the Mozilla Web Dev blog about getting involved.
On it, you&#8217;ll find information about some of our biggest projects, including Addons and Support. There are links to the project pages on the Mozilla Wiki, names of people to contact including IRC handles, and links to the source, tests and bug [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve got a new page on the Mozilla Web Dev blog about <a href="http://blog.mozilla.com/webdev/get-involved/">getting involved</a>.</p>
<p>On it, you&#8217;ll find information about some of our biggest projects, including <a href="http://addons.mozilla.org/">Addons</a> and <a href="http://support.mozilla.com/">Support</a>. There are links to the project pages on the <a href="http://wiki.mozilla.org/">Mozilla Wiki</a>, names of people to contact including IRC handles, and links to the source, tests and bug lists.</p>
<p>This page is a starting point. At the bottom you&#8217;ll find a link to a list of (hopefully) <a href="https://wiki.mozilla.org/Websites">all the websites we maintain</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/getting-involved-with-mozilla-web-dev-306/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mozilla Web Development is Open Source</title>
		<link>http://coffeeonthekeyboard.com/mozilla-web-development-is-open-source-303/</link>
		<comments>http://coffeeonthekeyboard.com/mozilla-web-development-is-open-source-303/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 04:28:17 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[contribute]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[webdev]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=303</guid>
		<description><![CDATA[At Mozilla, our web development projects are open source, publicly available, and interested in community contributions.
This is one of those things that makes absolute sense when you hear it, but you may have never heard, or thought, of it before.
It&#8217;s not terribly well-publicized—that&#8217;s something Mike Morgan and I are going to start working on this [...]]]></description>
			<content:encoded><![CDATA[<p>At Mozilla, our web development projects are open source, publicly available, and interested in community contributions.</p>
<p>This is one of those things that makes absolute sense when you hear it, but you may have never heard, or thought, of it before.</p>
<p>It&#8217;s not terribly well-publicized—that&#8217;s something <a href="http://morgamic.com/">Mike Morgan</a> and I are going to start working on this week—but there are ways you can get involved:</p>
<ul>
<li>There&#8217;s <a href="https://wiki.mozilla.org/Webdev">info about most, if not all, our current projects on the Mozilla Wiki</a>.</li>
<li>An <a href="https://bugzilla.mozilla.org/query.cgi?format=advanced">advanced search in Bugzilla</a> can tell you a lot about what&#8217;s going on.</li>
<li>You can find web dev people <a href="http://irc.mozilla.org/">on IRC</a> in #webdev, #sumodev, and a few others. (I&#8217;m jsocol on irc.mozilla.org.)</li>
</ul>
<p>Why would you want to contribute to Mozilla web development projects?</p>
<ul>
<li>You <a href="http://www.flickr.com/groups/owdposter/">care about the web</a>, and making it better.</li>
<li>Our websites are used by <a href="http://blog.mozilla.com/metrics/">millions of people</a>.</li>
<li>Because of that, we work at scales most developers don&#8217;t usually get to see.</li>
</ul>
<p>Hopefully I&#8217;ll have something to add by the end of the week, but in the meantime, come on over and say &#8220;hi&#8221; on IRC!</p>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/mozilla-web-development-is-open-source-303/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>(Don&#8217;t) Close Firefox with Last Tab</title>
		<link>http://coffeeonthekeyboard.com/dont-close-firefox-with-last-tab-296/</link>
		<comments>http://coffeeonthekeyboard.com/dont-close-firefox-with-last-tab-296/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 07:01:46 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[about:config]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://coffeeonthekeyboard.com/?p=296</guid>
		<description><![CDATA[Prior to Firefox 3.5, the default behavior of closing the last tab was to leave a blank tab. That changed in Firefox 3.5, and the default behavior is now to close the whole window with the last tab. If you&#8217;re on Windows or tend to close tabs with Ctrl-W, like me, this can be pretty [...]]]></description>
			<content:encoded><![CDATA[<p>Prior to Firefox 3.5, the default behavior of closing the last tab was to leave a blank tab. That changed in Firefox 3.5, and the default behavior is now to close the whole window with the last tab. If you&#8217;re on Windows or tend to close tabs with Ctrl-W, like me, this can be pretty annoying if you forget about it, what with reopening the browser and all.</p>
<p>Fortunately, it&#8217;s easy to change.</p>
<p>Venture into about:config. Go to the address bar and enter &#8220;about:config&#8221; and press enter. You&#8217;ll see a long list and at the top, a text box called &#8220;Filter:&#8221;</p>
<p><img class="aligncenter size-full wp-image-297" title="closewindowwithlasttab" src="http://coffeeonthekeyboard.com/wp-content/uploads/2009/09/closewindowwithlasttab.png" alt="closewindowwithlasttab" width="250" height="182" /><strong>Buyer Beware here</strong>. You probably saw a warning when you tried to go to about:config. That&#8217;s because you can significantly alter the behavior of Firefox here, and you need to be either very careful about what you change, or very confident in your ability to fix it.</p>
<p>Enter &#8220;tabs&#8221; into the filter and you&#8217;ll see a list like the picture above. There may be more items depending on the <a href="http://addons.mozilla.com/">addons</a> you have installed. Now look for &#8220;browser.tabs.closeWindowWithLastTab&#8221; and double click it. It should turn bold, and in the right columns it will say &#8220;user set&#8221; &#8220;boolean&#8221; &#8220;false&#8221;.</p>
<p>That&#8217;s it!</p>
<p>Of course, if you&#8217;re not comfortable mucking about in about:config, or you also want to restore the <em>close</em> button to that last tab, there&#8217;s an <a href="https://addons.mozilla.org/en-US/firefox/addon/12991">addon</a>* for that.</p>
<p>* Of course, I haven&#8217;t used, and can&#8217;t vouch for, that addon, but it&#8217;s there.</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 125px; width: 1px; height: 1px;"><img src="file:///C:/Users/James/AppData/Local/Temp/moz-screenshot-2.png" alt="" /></div>
]]></content:encoded>
			<wfw:commentRss>http://coffeeonthekeyboard.com/dont-close-firefox-with-last-tab-296/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
