<?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>All Night Diner &#187; code</title>
	<atom:link href="http://micropipes.com/blog/tag/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://micropipes.com/blog</link>
	<description>because at 3am anything sounds good</description>
	<lastBuildDate>Tue, 10 Apr 2012 17:38:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>AMO 2011 Development Visualized</title>
		<link>http://micropipes.com/blog/2011/05/15/amo-2011-development-visualized/</link>
		<comments>http://micropipes.com/blog/2011/05/15/amo-2011-development-visualized/#comments</comments>
		<pubDate>Sun, 15 May 2011 23:48:36 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=233</guid>
		<description><![CDATA[I was playing around with gource this weekend while watching the TSL 3 Finals and pointed it at addons.mozilla.org&#8217;s source repository. I sped it up to display 1 day of commits per second and piped it all to ffmpeg to make a video. It turned out pretty well so here is addons.mozilla.org development so far [...]]]></description>
			<content:encoded><![CDATA[<p>I was playing around with <a href="http://code.google.com/p/gource/">gource</a> this weekend while watching the <a href="http://www.pokerstrategytsl3.com/">TSL 3 Finals</a> and pointed it at <a href="https://github.com/jbalogh/zamboni">addons.mozilla.org&#8217;s source repository</a>.  I sped it up to display 1 day of commits per second and piped it all to ffmpeg to make a video.  </p>
<p>It turned out pretty well so here is addons.mozilla.org development so far for 2011 (in HD!):</p>
<p><video width="1280" height="720" controls preload="none"><br />
    <source src="http://people.mozilla.org/~clouserw/public/blog/amo-2011-development.ogv" type='video/ogg; codecs="theora"'><br />
</video><br />
(Warning: prefetching is off but if you click play you&#8217;re in for an 80MB video.)</p>
<p>The gource docs are easy to read if you want to do this for your project, but for the record this is what I ran:<br />
<code><br />
gource --viewport 1280x720 \<br />
       --user-image-dir ~/sandbox/zamboni/.git/avatar/ \<br />
       --title "addons.mozilla.org" \<br />
       --auto-skip-seconds 1 \<br />
       --seconds-per-day 1 \<br />
       --start-position .715 \<br />
       --max-file-lag 0.5 \<br />
       --max-files 5000 \<br />
       --camera-mode track \<br />
       -o -<br />
</code></p>
<p>Piped to:<br />
<code><br />
ffmpeg -y \<br />
       -r 60 \<br />
       -f image2pipe \<br />
       -vcodec ppm \<br />
       -i - \<br />
       -vcodec libtheora \<br />
       -b 10000K \<br />
       ~/out.ogv<br />
</code></p>
<p>That gave me a 180MB uncompressed ogv.  The uncompressed version looks far nicer, but that&#8217;s a lot of bandwidth for a random video so I cut it down with ffmpeg2thoerea (anyone know the switch to do this directly in the ffmpeg command?):<br />
<code><br />
ffmpeg2theora -v 4<br />
              ~/out.ogv<br />
              --optimize<br />
              --noaudio<br />
              -o amo-2011-development.ogv<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2011/05/15/amo-2011-development-visualized/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://people.mozilla.org/~clouserw/public/blog/amo-2011-development.ogv" length="82392684" type="video/ogg" />
		</item>
		<item>
		<title>Status Watch: An add-on for noticing HTTP error codes</title>
		<link>http://micropipes.com/blog/2011/02/10/status-watch-an-add-on-for-noticing-http-error-codes/</link>
		<comments>http://micropipes.com/blog/2011/02/10/status-watch-an-add-on-for-noticing-http-error-codes/#comments</comments>
		<pubDate>Fri, 11 Feb 2011 05:15:24 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[add-ons]]></category>
		<category><![CDATA[builder]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=189</guid>
		<description><![CDATA[Often on complex pages with many assets it can be easy to overlook assets which don&#8217;t load. Usually they are minor JS, CSS, or tracking pixels which aren&#8217;t noticed until you&#8217;ve spent way too long trying to track down the problem (or a month later you log into your stats dashboard to discover you haven&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>Often on complex pages with many assets it can be easy to overlook assets which don&#8217;t load.  Usually they are minor JS, CSS, or tracking pixels which aren&#8217;t noticed until you&#8217;ve spent way too long trying to track down the problem (or a month later you log into your stats dashboard to discover you haven&#8217;t been collecting stats).</p>
<p>With the launch of the new <a href="https://builder.addons.mozilla.org">Add-on Builder</a> (still an alpha product, but usable) I decided to make my first Jetpack to fix this.</p>
<p>In only about <a href="https://builder.addons.mozilla.org/addon/1000273/latest/">20 lines of code</a> I was able to look for any 4xx or 5xx errors in the HTTP traffic and show a brief notification to the user about what went wrong and where.  The builder was a great development experience (lack of documentation aside) and was a breeze to do something relatively complex.</p>
<p>If you&#8217;ve wanted a similar add-on, feel free to use <a href="https://addons.mozilla.org/en-US/firefox/addon/status-watch/">Status Watch</a>.  It&#8217;s a Jetpack so you&#8217;ll need Firefox 4, but on the bright side, you won&#8217;t even need to restart the browser.  Just click and go.</p>
<p><em>I&#8217;ve had some requests to support a whitelist of sites so you don&#8217;t get notifications all over the web and I&#8217;ll add that when I get time.  It&#8217;s surprising how many sites have 403s and 404s though.</em></p>
<p>Update 2011-02-17:  Version 2 is on AMO now which supports a whitelist.  See the <a href="https://addons.mozilla.org/en-US/firefox/addon/status-watch/">AMO page</a> for details.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2011/02/10/status-watch-an-add-on-for-noticing-http-error-codes/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>md5verify: A script to automatically verify file integrity</title>
		<link>http://micropipes.com/blog/2011/01/30/md5verify-a-script-to-automatically-verify-file-integrity/</link>
		<comments>http://micropipes.com/blog/2011/01/30/md5verify-a-script-to-automatically-verify-file-integrity/#comments</comments>
		<pubDate>Mon, 31 Jan 2011 06:36:01 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=178</guid>
		<description><![CDATA[I have a lot of files on my computer. Email archives, personal documents, stuff for work, photos I&#8217;ve taken&#8230;the list goes on &#8211; I&#8217;m sure most people reading this are in a similar boat. On occasion I&#8217;ve found some files to be missing or corrupt which is disturbing but is probably something to be expected. [...]]]></description>
			<content:encoded><![CDATA[<p>I have a lot of files on my computer.  Email archives, personal documents, stuff for work, photos I&#8217;ve taken&#8230;the list goes on &#8211; I&#8217;m sure most people reading this are in a similar boat.  On occasion I&#8217;ve found some files to be missing or corrupt which is disturbing but is probably something to be expected.  The bad part is, I keep backups, but I rotate them out when they reach a certain age which means if I don&#8217;t notice a file is corrupt or missing I&#8217;ll eventually lose it forever.</p>
<p>I stayed up late a few nights ago and wrote <a href="http://github.com/clouserw/scripts/blob/master/md5verify.py">a script to raise an alert when something has changed</a>.  On its first run the script will recursively walk a directory tree hashing each file and storing the hashes in the directory (in an md5sum compatible formatted file).  On subsequent runs it will begin tracking new files automatically but it will also print messages for missing and changed files.  By saving the checksums in each directory it becomes portable &#8211; you can copy a directory somewhere else and still be able to verify nothing changed (a quick <em>md5sum -c checksums.txt</em> will let you know).</p>
<p>By default the script only prints messages when it sees something fishy so it&#8217;s perfect to drop into cron and it uses exit statuses so it&#8217;ll work for nagios too.  I&#8217;ve been running it for a few months and have found a couple files that have changed &#8211; nothing critical yet but it&#8217;s nice to know it&#8217;s there.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2011/01/30/md5verify-a-script-to-automatically-verify-file-integrity/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>CLI Split Windows in Vim</title>
		<link>http://micropipes.com/blog/2010/08/13/cli-split-windows-in-vim/</link>
		<comments>http://micropipes.com/blog/2010/08/13/cli-split-windows-in-vim/#comments</comments>
		<pubDate>Fri, 13 Aug 2010 21:36:19 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[blah blah]]></category>
		<category><![CDATA[open web]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=170</guid>
		<description><![CDATA[I use split windows, both horizontally and vertically, in Vim all the time. I&#8217;ve always wanted to be able to split the window and then start a command line shell within that window but up until now that has just been a dream. My friend sent me a link to conque this morning which I&#8217;m [...]]]></description>
			<content:encoded><![CDATA[<p>I use split windows, both horizontally and vertically, in <a href="http://www.vim.org/">Vim</a> all the time.  I&#8217;ve always wanted to be able to split the window and then start a command line shell within that window but up until now that has just been a dream.</p>
<p><a href="http://hopson.ws/blog/">My friend</a> sent me a link to <a href="http://code.google.com/p/conque/">conque</a> this morning which I&#8217;m so taken with that it&#8217;s prompted me to drop coding and write a blog post.</p>
<p>Conque lets me do exactly what I&#8217;ve wanted, create shells within Vim.  In insert mode you interact with the shell as expected.  In normal mode you can scroll back through your history, yank text into buffers, paste and manipulate text.  Best thing ever.</p>
<p><a href="http://micropipes.com/blog/wp-content/img/vim_cli.png"><img src="http://micropipes.com/blog/wp-content/img/vim_cli_small.png" /></a><br />
<caption>Two files open on the left, three shells on the right; iPython, MySQL, and Django&#8217;s web server &#8211; all with syntax highlighting.</caption>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/08/13/cli-split-windows-in-vim/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>addons.mozilla.org ♥s unit tests.  Again.</title>
		<link>http://micropipes.com/blog/2010/05/03/addons-mozilla-org-%e2%99%a5s-unit-tests-again/</link>
		<comments>http://micropipes.com/blog/2010/05/03/addons-mozilla-org-%e2%99%a5s-unit-tests-again/#comments</comments>
		<pubDate>Mon, 03 May 2010 17:34:44 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=142</guid>
		<description><![CDATA[AMO has had an on-again off-again relationship with unit tests. A little over a year ago we had a thousand unit tests that sort of, mostly, ran. The problem is, PHP unit testing just isn&#8217;t as good as it should be. CakePHP relies on SimpleTest, one of the main PHP test suites. It worked relatively [...]]]></description>
			<content:encoded><![CDATA[<p><a href="https://addons.mozilla.org">AMO</a> has had an on-again off-again relationship with unit tests.  A little over a year ago we had <a href="http://micropipes.com/blog/2009/04/09/addonsmozillaorg-celebrates-1000-passing-unit-tests/">a thousand unit tests</a> that sort of, mostly, ran.  The problem is, PHP unit testing just isn&#8217;t as good as it should be.  CakePHP relies on <a href="http://www.simpletest.org/">SimpleTest</a>, one of the main PHP test suites.  It worked relatively well for a small number of tests, but as our suite grew, so did our troubles.</p>
<p>Our main issue was hitting a memory limit or the max execution time.  We hit the limits often for a variety of reasons, some legitimate bugs, and some because we tried to hack around things to make the tests run.  If we change the limits we affect the tests because they are running within the same environment.  There wasn&#8217;t really a concept of fixtures then, although it looks like <a href="http://bakery.cakephp.org/articles/view/testing-models-with-cakephp-1-2-test-suite">CakePHP has stepped up there</a>.  The simple test web runner was hard to use and the mock objects were sometimes a little too mocked and missing some attributes.</p>
<p>All in all it was a heroic effort to get that many tests, but we didn&#8217;t maintain it because they were so slow to write and difficult to run.  Testing can be a pain to write, sure, but it shouldn&#8217;t be a burden like that.  Enter <a href="http://docs.djangoproject.com/en/dev/topics/testing/">Django&#8217;s testing suite</a> (built on top of <a href="http://docs.python.org/library/unittest.html">Python&#8217;s unittest</a>).  It has most of our complaints handled out of the box.  It&#8217;s very well documented, considers a lot of aspects of testing, supports fixtures, a built-in client, etc.  It&#8217;s a well thought out framework to build tests on.</p>
<p>We&#8217;re being more vigilant about requiring tests this time around, but they also aren&#8217;t as frustrating to write.  When you write them they actually work and they stay working.  Most of what you want is built in already.  For example, I wrote the password reset form we needed on AMO in Django.  With CakePHP and SimpleTest I&#8217;d have no idea how to test that the email was actually working.  It&#8217;s apparently possible <a href="http://www.curioussymbols.com/simplemail/">with a SimpleTest add-on</a> and enough code that I have to scroll in my browser.  With Django&#8217;s test suite the actual code was 5 lines, 3 of which were assertions:</p>
<pre><code class="python">
    def test_request_success(self):
        self.client.post('/en-US/firefox/users/pwreset',
                        {'email': self.user.email})

        eq_(len(mail.outbox), 1)
        assert mail.outbox[0].subject.find('Password reset') == 0
        assert mail.outbox[0].body.find('pwreset/%s' % self.uidb36) > 0
</code></pre>
<p>With the power of the new test suite we&#8217;re once again writing and maintaining our unit tests &#8211; currently at around 390 tests and increasing steadily.  Plenty of people have written about why unit tests are important so I won&#8217;t belabor the point, but I will mention that it&#8217;s a great feeling to be able to commit something and be confident it hasn&#8217;t affected other parts of the site.  It&#8217;s almost as good of a feeling when you write your code and a completely different test fails pointing out a case that you didn&#8217;t even consider but one that would soak up developer time trying to debug down the road.  </p>
<p>Building on a foundation that takes testing seriously is great.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/05/03/addons-mozilla-org-%e2%99%a5s-unit-tests-again/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Continuous Integration comes to AMO</title>
		<link>http://micropipes.com/blog/2010/04/07/continuous-integration-comes-to-amo/</link>
		<comments>http://micropipes.com/blog/2010/04/07/continuous-integration-comes-to-amo/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 14:54:13 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[statistics]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=139</guid>
		<description><![CDATA[It&#8217;s time to hail another milestone for AMO in our epic push for improvements in 2010. This time I&#8217;m happy to announce our Hudson continuous integration server which has been humming along for a few months. Hudson Integration Screenshot. Click to enlarge. AMO is the first Mozilla Webdev site to use continuous integration, and it&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s time to hail another milestone for <a href="https://addons.mozilla.org/">AMO</a> in our <a href="http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/">epic push for improvements in 2010</a>.  This time I&#8217;m happy to announce our <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/">Hudson continuous integration server</a> which has been humming along for a few months.</p>
<p><a href="http://micropipes.com/blog/wp-content/img/hudson_screenshot.png"><img src="http://micropipes.com/blog/wp-content/img/hudson_screenshot_small.png" title="Hudson Summary Screenshot" style="border:1px solid #000; padding:10px;" /></a></p>
<caption>Hudson Integration Screenshot.  Click to enlarge.</caption>
<p>AMO is the first Mozilla Webdev site to use continuous integration, and it&#8217;s been a long time coming.  With the way it&#8217;s currently configured we&#8217;ve got <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/512/cobertura/?">code coverage trending</a>, <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/512/testReport/?">unit test trending</a>, <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/512/violations/?">code quality trending</a>, as well as detailed reports for all the above for every single check in.</p>
<p>If anything fails or oversteps a threshold our IRC bot complains and we can get it fixed up quickly.  It&#8217;s a boon to productivity to know that all the code being checked in is being tested automatically, plus it gives everyone a stable state to compare to.</p>
<p>Thanks to everyone that helped get Hudson going, from the <a href="http://blog.hudson-ci.org/">people that write it</a>, to <a href="http://blog.mozilla.com/it/">the IT team that keeps it alive</a>, to <a href="http://blog.mozilla.com/webdev/">the webdev team</a> that helped work out the kinks.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/04/07/continuous-integration-comes-to-amo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Libraries to connect to a Citrix NetScaler or Zeus Traffic Manager</title>
		<link>http://micropipes.com/blog/2010/03/23/libraries-to-connect-to-a-citrix-netscaler-or-zeus-traffic-manager/</link>
		<comments>http://micropipes.com/blog/2010/03/23/libraries-to-connect-to-a-citrix-netscaler-or-zeus-traffic-manager/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 18:56:57 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[scalability]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=133</guid>
		<description><![CDATA[The first front end cache we used on AMO was the Citrix NetScaler. I&#8217;ve complained about it&#8217;s API before but apparently never announced the library I wrote to purge items from the cache. So, a little late, but I have some reusable PHP code that will talk to your NetScaler and let you expire objects. [...]]]></description>
			<content:encoded><![CDATA[<p>The first front end cache we used on <a href="https://addons.mozilla.org/">AMO</a> was the <a href="http://www.citrix.com/English/ps2/products/product.asp?contentID=21679">Citrix NetScaler</a>.  I&#8217;ve <a href="http://micropipes.com/blog/2008/07/14/planning-your-api-is-important/">complained about it&#8217;s API before</a> but apparently never announced the library I wrote to purge items from the cache.  So, a little late, but I have <a href="http://viewvc.svn.mozilla.org/vc/libs/ns-api/">some reusable PHP code that will talk to your NetScaler</a> and let you expire objects.</p>
<p>We hit some limitations with the NetScaler that we weren&#8217;t happy with.  Cost aside, it ignored some pretty standard stuff like the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44">HTTP Vary Header</a>.  After working around that for years we switched to the horizontally scalable <a href="http://www.zeus.com/products/traffic-manager/index.html">Zeus Traffic Manager</a> (at that time, referred to as ZXTM).  We&#8217;ve been pleased with our choice and six months ago I wrote a <a href="http://viewvc.svn.mozilla.org/vc/libs/zxtm-api/">similar PHP library that allows you to connect to Zeus&#8217;s API</a>.  Time and priorities being what they are, we never implemented it in production.</p>
<p>Finally, the real point to this post, last night I wrote a <a href="http://github.com/clouserw/hera">python library that will expire content from Zeus</a>.  We&#8217;ll roll this into our migration and waiting on content to expire from Zeus should be a thing of the past.</p>
<p>As always, if you can use the libraries, feel free.  They all have READMEs with examples.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/03/23/libraries-to-connect-to-a-citrix-netscaler-or-zeus-traffic-manager/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Maintaining localization between Python and PHP (it&#8217;s not fun)</title>
		<link>http://micropipes.com/blog/2010/03/08/maintaining-localization-between-python-and-php-its-not-fun/</link>
		<comments>http://micropipes.com/blog/2010/03/08/maintaining-localization-between-python-and-php-its-not-fun/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 22:42:00 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[L10n]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=115</guid>
		<description><![CDATA[I reached my hand into the barrel of problems our migration to Python is going to cause and came up with Localization. It figures. First out of the chute was the .po files. It turns out the actual formatting is different between the two languages. PHP uses %1$s for its substitutions, but python uses either [...]]]></description>
			<content:encoded><![CDATA[<p>I reached my hand into the barrel of problems <a href="http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/">our migration to Python</a> is going to cause and came up with Localization.  It figures.</p>
<p>First out of the chute was the .po files.  It turns out the actual formatting is different between the two languages.  PHP uses <em>%1$s</em> for its substitutions, but python uses either named variables like <em>(num)s</em> or integers like <em>{0}</em>.  For the record, they both support <em>%s</em> when you don&#8217;t need to order the substitutions.<br />
PHP example:<br />
<code>I have %2$s apples and %1$s oranges</code><br />
Python example:<br />
<code>I have {1} apples and {0} oranges</code></p>
<p>Since I&#8217;ve worked with the <a href="http://translate.sourceforge.net/wiki/">Translate Toolkit</a> before, I decided to write a script to convert between the two formats.  If you find yourself in the same unfortunate boat as me, behold<br />
<a href="http://translate.svn.sourceforge.net/viewvc/translate/src/trunk/translate/tools/phppo2pypo.py?view=markup">phppo2pypo</a> and <a href="http://translate.svn.sourceforge.net/viewvc/translate/src/trunk/translate/tools/pypo2phppo.py?view=markup">pypo2phppo</a> to convert between the two types.</p>
<p>Crisis averted, right?  Oh, that&#8217;s just scratching the surface.  Remember <a href="http://micropipes.com/blog/2008/07/09/adding-context-to-amo-po-files/">how happy I was that PHP finally started supporting msgctxt</a>?  Well, Python has had <a href="http://bugs.python.org/issue2504">a patch for it since 2008</a> but no one has bothered to land it.  I wrote a new <a href="http://github.com/clouserw/tower/blob/master/l10n/__init__.py">ugettext() and ungettext()</a> that recognizes context in the .po files.  To use simply do: <em>from l10n import ugettext as _</em> at the top of your file.</p>
<p>Along with adding msgctxt support, those two functions also collapse consecutive white space.  We&#8217;re using <a href="http://jinja.pocoo.org/2/">Jinja2</a> with <a href="http://babel.edgewall.org/">Babel</a> and the <a href="http://jinja.pocoo.org/2/documentation/extensions">i18n extension</a> as our template engine.  Jinja2 has a concept of stripping white space from the beginning or end of a string but does nothing about the middle.  A paragraph of text in a Jinja2 template would look like:<br />
<code><br />
  {% trans -%}Mozilla is providing links to these applications<br />
  as a courtesy, and makes no representations regarding the<br />
  applications or any information related thereto. Any questions,<br />
  complaints or claims regarding the applications must be<br />
  directed to the appropriate software vendor.<br />
  {%- endtrans %}<br />
</code></p>
<p>That&#8217;s a decent looking template, right?  Yeah, well, when Babel extracts that, it includes all the line breaks too, giving you something <a href="http://bitbucket.org/plurk/solace/src/tip/solace/i18n/messages.pot#cl-625">like this</a>.  The localizers would revolt if I sent them that, so I added in auto white-space collapsing.  Getting Babel to use the new functions means <a href="http://github.com/clouserw/tower/blob/master/tower/management/commands/extract.py">a new extraction script</a>.</p>
<p>At this point, we&#8217;re extracting strings from our new code and we can convert between Python and PHP files.  All we need now is a Frankenstein mix of xgettext functions to act as glue.  Meet the <a href="http://github.com/clouserw/tower/blob/master/l10n/management/commands/amalgamate.py">amalgamate script</a> that uses the pypo2php scripts, concatenates the .pot files, and merge updates each locales .po file.  After that it&#8217;s <a href="http://viewvc.svn.mozilla.org/vc?revision=63671&#038;view=revision">quick tweaks to the build scripts</a> to create z-messages.po files and we&#8217;re done.</p>
<p>So, all that said, the new process for L10n, while we&#8217;re in this transitional phase, is:</p>
<ol>
<li>From the PHP code, run <em>locale/extract-po-remora.sh</em>.  That pulls everything from all the PHP files, creates <em>locale/r-keys.pot</em>, updates the messages.po file for each locale, and compiles them.  Life used to be so simple.</li>
<li>From the python code, make sure you&#8217;re up to date, then run <em>./manage.py extract</em>.  That will pull everything from the python code and templates and create <em>locale/z-keys.pot</em>.</li>
<li>Run <em>./manage.py amalgamate</em>.  That will merge the z-keys.pot into the PHP messages.po files.</li>
<li>Localizers can make their changes as usual, and commit back to messages.po.</li>
<li>From PHP, <em>locale/copy-to-zamboni.py locale</em> will create z-messages.po files in the Python format. We could skip right to .mo files, but in case something goes wrong I want to see the .po files.</li>
<li>Then, like today, <em>locale/compile-mo.sh locale</em> will compile all the .po files.</li>
</ol>
<p>After all those steps are done, we&#8217;ve got duplicate .mo files, aside from formatting, and each application can look at its own .mo to get the strings it needs.  All this code is just a big band-aid and there are plenty of things that are more fun than juggling L10n between two applications across two <abbr title="Revision Control Systems">RCS</abbr>s.  But we knew what we were getting in to.  I&#8217;ll post something more positive later to help justify it. <img src='http://micropipes.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/03/08/maintaining-localization-between-python-and-php-its-not-fun/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Automating &#8220;Thinking of you&#8221;</title>
		<link>http://micropipes.com/blog/2009/07/20/automating-thinking-of-you/</link>
		<comments>http://micropipes.com/blog/2009/07/20/automating-thinking-of-you/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 17:53:39 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=81</guid>
		<description><![CDATA[I had an idea a few weeks ago. I&#8217;ve got a bunch of great photos on my computer that no one ever sees unless we meet in person. Sure, we&#8217;ve got flickr and social networking sites, but I&#8217;m talking about an old photo that someone only saw once in passing, or a favorite shot from [...]]]></description>
			<content:encoded><![CDATA[<p>I had an idea a few weeks ago.  I&#8217;ve got a bunch of great photos on my computer that no one ever sees unless we meet in person.  Sure, we&#8217;ve got <a href="http://www.flickr.com/">flickr</a> and social networking sites, but I&#8217;m talking about an old photo that someone only saw once in passing, or a favorite shot from summer while you&#8217;re huddled over your heater wondering when the sun is coming back.</p>
<p>I can look at them any time, and there are a few on flickr that other people can look at, but what about people that aren&#8217;t tech savvy or are really busy and get caught up in the daily grind?</p>
<p>I was thinking, the answer can be a really simple script running from cron, say, weekly.  It picks a random photo from a directory and emails it to a group of people.  That&#8217;s it.  The idea is:</p>
<ul>
<li>it&#8217;s low tech compared to RSS feeds and social networking sites.  This &#8220;just works&#8221; with the tools people (potentially, low-tech people) are already used to using.</li>
<li>in a similar vein, commenting and discussion are built in if you feel like it.</li>
<li>it&#8217;s focused on the people on the CC list.  Sending out an old photo that is relevant just to those people has a lot more effect than one scrolling by on flickr.  It&#8217;s got a personal touch.</li>
<li>it&#8217;s automatic.  You wake up Monday morning, drag yourself to work, and there is a photo from 15 years ago in your inbox and you can laugh about how bad your hair was.  Awesome.</li>
</ul>
<p>So, I thought I would try it and cooked up <a href="http://svn.micropipes.com/audreytoo/audreytoo.py">audreytoo</a>.  Basically, you seed a directory with <em>copies</em> of the pictures you want to send out, add the script to a cron job, and it does it&#8217;s thing.  There are a couple other features in the script that you could look at if you want to get fancier.</p>
<p>I realize there is some irony in using an automated script to say &#8220;I&#8217;m thinking of you&#8221; but as long as I&#8217;m on the CC list it&#8217;s still true. <img src='http://micropipes.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   Anyway, I&#8217;m sharing the code in case anyone else can find value in it.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2009/07/20/automating-thinking-of-you/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Committing to SVN securely from a web application</title>
		<link>http://micropipes.com/blog/2008/09/19/committing-to-svn-securely-from-a-web-application/</link>
		<comments>http://micropipes.com/blog/2008/09/19/committing-to-svn-securely-from-a-web-application/#comments</comments>
		<pubDate>Fri, 19 Sep 2008 22:29:58 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[SVN]]></category>
		<category><![CDATA[Verbatim]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=56</guid>
		<description><![CDATA[Verbatim is the second project I&#8217;ve been the lead on recently where the requirements included people committing to SVN as themselves via the application. At first glance this means storing the authentication tokens of the user in plain text since we&#8217;ll need to pass them along to SVN whenever they commit. I wasn&#8217;t happy with [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wiki.mozilla.org/Verbatim">Verbatim</a> is the second project I&#8217;ve been the lead on recently where the requirements included people committing to <abbr title="Subversion">SVN</abbr> as themselves via the application.  At first glance this means storing the authentication tokens of the user in plain text since we&#8217;ll need to pass them along to SVN whenever they commit.  I wasn&#8217;t happy with that solution so after a bit of thinking we came up with an idea that leaves everything encrypted and doesn&#8217;t cache any credentials.  It involved minimal code in Verbatim and minor work on the SVN server.</p>
<p>On the SVN server the first thing we did was to create a special Verbatim user that can commit to SVN via SSH using a generated key.  We copied this key to the Verbatim host which allowed us to commit as the verbatim user without typing a username or password.</p>
<p>The only thing that was added to the Verbatim code was <a href="http://sourceforge.net/mailarchive/forum.php?thread_name=ADA2D058-904B-44F0-8301-21334A7B6E02%40mozilla.com&#038;forum_name=translate-pootle">a patch that Dan Schafer cooked up</a> that sets an SVN revision property, <em>translate:author</em>, to the name of the current user.  When the user clicks &#8220;commit&#8221; this property is set and sent along with the commit.</p>
<p>At this point we could commit from the application but it still goes to the application as the Verbatim user.  We used <a href="http://svnbook.red-bean.com/en/1.4/svn-book.html#svn.ref.reposhooks">SVN&#8217;s hooks</a> to take the next step.</p>
<p>The first script we changed was the pre-revprop-change hook.  This controls what special revision properties a user can modify when they commit.  <a href="https://bugzilla.mozilla.org/attachment.cgi?id=337775">Our script</a> adds the ability to modify svn:author and translate:author.  Before allowing the modifications the script checks if the user committing is the special verbatim user to prevent anyone from committing as someone else.</p>
<p>Next we added a <a href="https://bugzilla.mozilla.org/attachment.cgi?id=339184">post-commit script</a> that looks for the translate:author property.  If it&#8217;s found it will take that value, replace svn:author, and remove translate:author; effectively making whatever was in translate:author the real author.  This is a non-versioned change which means there is no commit that needs to happen &#8211; the new author is set immediately.</p>
<p>With these scripts in place we can commit as anyone from the application and everyone&#8217;s credentials stay encrypted and secure.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2008/09/19/committing-to-svn-securely-from-a-web-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

