<?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>Fazal Majid&#039;s low intensity weblog &#187; Mylos</title>
	<atom:link href="http://majid.info/blog/tag/mylos/feed/" rel="self" type="application/rss+xml" />
	<link>http://majid.info/blog</link>
	<description>Sporadic pontification</description>
	<lastBuildDate>Thu, 05 Jan 2012 07:15:23 +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>Leica Monovid review</title>
		<link>http://majid.info/blog/leica-monovid-review/</link>
		<comments>http://majid.info/blog/leica-monovid-review/#comments</comments>
		<pubDate>Sat, 24 Oct 2009 02:02:51 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Photo]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2009/10/23-1.html</guid>
		<description><![CDATA[Leica recently introduced the Monovid monocular. Monoculars are more compact than binoculars, but you lose stereo vision, which is why birdwatchers tend to shun them. I myself have a very strong director eye and correspondingly poor binocular vision, so this &#8230; <a href="http://majid.info/blog/leica-monovid-review/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Leica recently introduced the <a href="http://us.leica-camera.com/sport_optics/monovid/">Monovid</a> monocular. Monoculars are more compact than binoculars, but you lose stereo vision, which is why birdwatchers tend to shun them. I myself have a very strong director eye and correspondingly poor binocular vision, so this is not such a big deal for me.</p>
<p> <center><img width="549" height="640" src="http://majid.info/blog/wp-content/uploads/2009/10/monovid1.jpg" alt="Monovid"></center>
<p>The Monovid is supplied with an accessory screw-on close-up lens that reduces the minimum focus distance. This is useful for butterfly or hummingbird watchers, but the arrangement is clumsier than the <a href="http://minox.com/index.php?id=1309&amp;L=1">Minox Makroskop</a>.</p>
<p> <center><img width="427" height="640" src="http://majid.info/blog/wp-content/uploads/2009/10/monovid3.jpg" alt="Monovid"></center>
<p>The Monovid is essentially half of a pair of <a href="http://us.leica-camera.com/sport_optics/compact_binoculars/ultravid_25_br/">Ultravid 8&#215;20 BL</a> binoculars. The barrel is 3-4mm longer to accommodate the threads for the close-up lens, and it has a goiter-like knurled protrusion towards the end for focusing. The eyecup is the same, and can be either pulled out for normal viewing, or left in for eyeglass wearers. This is a far better arrangement than fold-up rubber eyecups. The leather case for the Monovid is quite bulky, and features a screw thread to hold the close-up lens as well as an ingenious ribbon that pulls the monocular out of the case when you flip the lid open. It also has a magnetic catch unlike the Ultravids&#8217; snap button.</p>
<p> <center><img width="505" height="640" src="http://majid.info/blog/wp-content/uploads/2009/10/monovid2.jpg" alt="Monovid and Ultravid"></center>
<p>Unsurprisingly, the performance is nearly identical, that is to say, stellar. The image is bright (most monoculars are in the 12-15mm aperture range). There is no hint of distortion or chromatic aberration across the field. It is quite sensitive to perfectly centered eye placement, specially when you are wearing eyeglasses, otherwise you will black out.</p>
<p>Sadly, the price is not half that of the binoculars, closer to two thirds. Considering that it is not all that much more compact and you lose stereo vision, if you are considering one, I would recommend the more versatile Ultravid 8&#215;20 BL (or the cheaper BR) instead. Another option to consider is the respected line of Zeiss monoculars (most are more compact than the Monovid, but the 8&#215;20 is nearly the same size and not as well built) or the slower but smaller Nikon &#8220;high grade&#8221; monocular series (unfortunately the 7&#215;15 has been discontinued, but old new stock is still readily available).</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/leica-monovid-review/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Just enough Weave</title>
		<link>http://majid.info/blog/just-enough-weave/</link>
		<comments>http://majid.info/blog/just-enough-weave/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 00:36:07 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2009/09/09-1.html</guid>
		<description><![CDATA[Note: I am keeping this code around for historical purposes, but it has not worked since Weave 1.0 RC2. I created this because Mozilla&#8217;s public sync servers were initially quite unreliable, but they have remedied the situation and performance problems &#8230; <a href="http://majid.info/blog/just-enough-weave/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p style="background-color: yellow;">Note: I am keeping this code around for historical purposes, but it has not worked since Weave 1.0 RC2. I created this because Mozilla&#8217;s public sync servers were initially quite unreliable, but they have remedied the situation and performance problems are a thing of the past. I also learned the inner workings of Weave/Firefox Sync in the process, and am satisfied as to the security of the system. Since I no longer use Firefox myself, I do not expect to ever revive this project. Feel free to take it over, otherwise you are best served by using Mozilla&#8217;s cloud.</p>
<p>Like most of my readers, I use multiple computers: my Mac Pro at home, my MacBook Air when on the road, 3 desktop PCs at work, a number of virtual machines, and so on. I have Firefox installed on all of them. The <a href="http://labs.mozilla.com/weave/">Mozilla Weave</a> extension allows me to sync bookmarks, passwords et al between them. Weave encrypts this data before uploading it to the server, but I do not like to rely on third-party web services for mission-critical functions (my Mozilla server was down last Monday, for instance, due to the surge of traffic from people returning to work and performing a full sync against 0.5). Through Weave 0.5, I ran <a href="http://majid.info/blog/?p=334">my own instance</a> of the Mozilla public Weave server version 0.3. Unfortunately, Weave 0.6 requires server version 0.5 and I had to upgrade.</p>
<p>The open-source Weave server is implemented in PHP. It doesn&#8217;t require Apache compiled with mod_dav as early versions did (I prefer to run <a href="http://wiki.nginx.org/Main">nginx</a>), but it is still a fairly gnarly piece of code that is anything but plug-and-play. Somehow I had managed to get version 0.3 running on my home server, but no amount of blundering around got me to a usable state with 0.5. I ended up deciding to implement a minimalist Weave server in Python, as it seemed less painful than continuing to struggle with the Mozilla spaghetti code, which confusingly features multiple pieces of code that appear to do exactly the same thing in three different places. Famous last words&#8230;</p>
<p>Three days of hacking later, I managed to get it working. 200 or so lines of Python code replaced approximately 12,000 lines of PHP. Of course, I am not trying to reproduce an entire public cloud infrastructure like Mozilla&#8217;s, just enough for my own needs, using the &#8220;simplest thing that works&#8221; principle. Interestingly, the Mozilla code includes a vestigial Python reference implementation of a Weave server for testing purposes. It does not seem to have been working for a while, though. I used it as a starting point but ended up rewriting almost everything. Here are the simplifying hypotheses:</p>
<ul>
<li>My weave server is meant for a single user (my wife prefers Safari)</li>
<li>It does not implement authentication, logging or SSL encryption — it is meant to be used behind a nginx (or Apache) reverse proxy that will perform these functions.</li>
<li>It has no configuration file. There are just three variables to set at the top of the source file.</li>
<li>It does not implement the full server protocol, just the parts that are actually used by the extension today.</li>
<li>More controversially, it does not even implement persistence, keeping all data in RAM instead. Python running on Solaris is very reliable, and the expected uptime of the server is likely months on end. If the server fails, the Firefoxes will just have to perform a full sync and reconciliation. Fortunately, that has been much improved in Weave 0.6, so the cost is minimal. This could even be construed as a security feature, since there is no data on disk to be misplaced. It would take catastrophically losing all my browsers simultaneously to risk data loss. Short of California falling into the ocean, that&#8217;s not going to happen, and if it does, I probably have more pressing concerns&#8230;</li>
</ul>
<p>The code could be extended fairly easily to lift these hypotheses, e.g. adding persistence or multiple user support using SQLite, PostgreSQL or MySQL.</p>
<p>Here is the server itself, <a href="http://majid.info/blog/wp-content/uploads/2009/09/weave_server.py">weave_server.py</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/local/bin/python</span>
<span style="color: #483d8b;">&quot;&quot;&quot;
  Based on tools/scripts/weave_server.py from
  http://hg.mozilla.org/labs/weave/
&nbsp;
  do the Simplest Thing That Can Work: just enough to get by with Weave 0.6
  - SSL, authentication and loggin are done by nginx or other reverse proxy
  - no persistence, in case of process failure do a full resync
  - only one user. If you need more, create multiple instances on different
    ports and use rewrite rules to route traffic to the right one
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>, <span style="color: #dc143c;">time</span>, <span style="color: #dc143c;">logging</span>, <span style="color: #dc143c;">socket</span>, <span style="color: #dc143c;">urlparse</span>, <span style="color: #dc143c;">httplib</span>, <span style="color: #dc143c;">pprint</span>
<span style="color: #ff7700;font-weight:bold;">try</span>:
  <span style="color: #ff7700;font-weight:bold;">import</span> simplejson <span style="color: #ff7700;font-weight:bold;">as</span> json
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ImportError</span>:
  <span style="color: #ff7700;font-weight:bold;">import</span> json
<span style="color: #ff7700;font-weight:bold;">import</span> wsgiref.<span style="color: black;">simple_server</span>
&nbsp;
URL_BASE = <span style="color: #483d8b;">'https://your.server.name/'</span>
<span style="color: #808080; font-style: italic;">#BIND_IP = ''</span>
BIND_IP = <span style="color: #483d8b;">'127.0.0.1'</span>
DEFAULT_PORT = <span style="color: #ff4500;">8000</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> HttpResponse:
  <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">code</span>, content=<span style="color: #483d8b;">''</span>, content_type=<span style="color: #483d8b;">'text/plain'</span><span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: black;">status</span> = <span style="color: #483d8b;">'%s %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">code</span>, <span style="color: #dc143c;">httplib</span>.<span style="color: black;">responses</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">code</span>, <span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">headers</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Content-type'</span>, content_type<span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'X-Weave-Timestamp'</span>, <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>timestamp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">content</span> = content <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">self</span>.<span style="color: black;">status</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> JsonResponse<span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span>:
  <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">OK</span>, value, content_type=<span style="color: #483d8b;">'application/json'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> HttpRequest:
  <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, environ<span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: black;">environ</span> = environ
    content_length = environ.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'CONTENT_LENGTH'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> content_length:
      stream = environ<span style="color: black;">&#91;</span><span style="color: #483d8b;">'wsgi.input'</span><span style="color: black;">&#93;</span>
      <span style="color: #008000;">self</span>.<span style="color: black;">contents</span> = stream.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>content_length<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">contents</span> = <span style="color: #483d8b;">''</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> timestamp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
  <span style="color: #808080; font-style: italic;"># Weave rounds to 2 digits and so must we, otherwise rounding errors will</span>
  <span style="color: #808080; font-style: italic;"># influence the &quot;newer&quot; and &quot;older&quot; modifiers</span>
  <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">round</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">time</span>.<span style="color: #dc143c;">time</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> WeaveApp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
  <span style="color: #483d8b;">&quot;&quot;&quot;WSGI app for the Weave server&quot;&quot;&quot;</span>
  <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span> = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> url_base<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;XXX should derive this automagically from self.request.environ&quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> URL_BASE
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> ts_col<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, col<span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'timestamps'</span>, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>col<span style="color: black;">&#93;</span> = <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>timestamp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> parse_url<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, path<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/0.5/'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">not</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/1.0/'</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span>
    command, args = path.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span>, <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>:<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> command, args
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> opts_test<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, opts<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'older'</span> <span style="color: #ff7700;font-weight:bold;">in</span> opts:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>opts<span style="color: black;">&#91;</span><span style="color: #483d8b;">'older'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__ge__</span>
    <span style="color: #ff7700;font-weight:bold;">elif</span> <span style="color: #483d8b;">'newer'</span> <span style="color: #ff7700;font-weight:bold;">in</span> opts:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>opts<span style="color: black;">&#91;</span><span style="color: #483d8b;">'newer'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__le__</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">True</span>
&nbsp;
  <span style="color: #808080; font-style: italic;"># HTTP method handlers</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> _handle_PUT<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, path, environ<span style="color: black;">&#41;</span>:
    command, args = <span style="color: #008000;">self</span>.<span style="color: black;">parse_url</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
    col, key = args.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">assert</span> command == <span style="color: #483d8b;">'storage'</span>
    val = <span style="color: #008000;">self</span>.<span style="color: black;">request</span>.<span style="color: black;">contents</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> val<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> == <span style="color: #483d8b;">'{'</span>:
      val = json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>val<span style="color: black;">&#41;</span>
      val<span style="color: black;">&#91;</span><span style="color: #483d8b;">'modified'</span><span style="color: black;">&#93;</span> = timestamp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
      val = json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>val, sort_keys=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span>col, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>key<span style="color: black;">&#93;</span> = val
    <span style="color: #008000;">self</span>.<span style="color: black;">ts_col</span><span style="color: black;">&#40;</span>col<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">OK</span><span style="color: black;">&#41;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> _handle_POST<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, path, environ<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
      status = <span style="color: #dc143c;">httplib</span>.<span style="color: black;">NOT_FOUND</span>
      <span style="color: #ff7700;font-weight:bold;">if</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/0.5/'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/1.0/'</span><span style="color: black;">&#41;</span>:
        command, args = <span style="color: #008000;">self</span>.<span style="color: black;">parse_url</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
        col = args.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
        vals = json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">request</span>.<span style="color: black;">contents</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> val <span style="color: #ff7700;font-weight:bold;">in</span> vals:
          val<span style="color: black;">&#91;</span><span style="color: #483d8b;">'modified'</span><span style="color: black;">&#93;</span> = timestamp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
          <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span>col, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>val<span style="color: black;">&#91;</span><span style="color: #483d8b;">'id'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span> = json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>val<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">ts_col</span><span style="color: black;">&#40;</span>col<span style="color: black;">&#41;</span>
        status = <span style="color: #dc143c;">httplib</span>.<span style="color: black;">OK</span>
    <span style="color: #ff7700;font-weight:bold;">finally</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span>status<span style="color: black;">&#41;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> _handle_DELETE<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, path, environ<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">assert</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/0.5/'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/1.0/'</span><span style="color: black;">&#41;</span>
    response = HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">OK</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> path.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/storage/0'</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">clear</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">elif</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/0.5/'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/1.0/'</span><span style="color: black;">&#41;</span>:
      command, args = <span style="color: #008000;">self</span>.<span style="color: black;">parse_url</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
      col, key = args.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
      <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> key:
        opts = <span style="color: #dc143c;">urlparse</span>.<span style="color: black;">parse_qs</span><span style="color: black;">&#40;</span>environ<span style="color: black;">&#91;</span><span style="color: #483d8b;">'QUERY_STRING'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">test</span> = <span style="color: #008000;">self</span>.<span style="color: black;">opts_test</span><span style="color: black;">&#40;</span>opts<span style="color: black;">&#41;</span>
        col = <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span>col, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> key <span style="color: #ff7700;font-weight:bold;">in</span> col.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
          <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">test</span><span style="color: black;">&#40;</span>json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>col<span style="color: black;">&#91;</span>key<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'modified'</span>, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
            <span style="color: #dc143c;">logging</span>.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'DELETE %s key %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>path, key<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">del</span> col<span style="color: black;">&#91;</span>key<span style="color: black;">&#93;</span>
      <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
          <span style="color: #ff7700;font-weight:bold;">del</span> <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span><span style="color: black;">&#91;</span>col<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>key<span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
          <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">NOT_FOUND</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> response
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> _handle_GET<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, path, environ<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/0.5/'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/1.0/'</span><span style="color: black;">&#41;</span>:
      command, args = <span style="color: #008000;">self</span>.<span style="color: black;">parse_url</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">handle_storage</span><span style="color: black;">&#40;</span>command, args, path, environ<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">elif</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/1/'</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">OK</span>, <span style="color: #008000;">self</span>.<span style="color: black;">url_base</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">elif</span> path.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/state'</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">OK</span>, <span style="color: #dc143c;">pprint</span>.<span style="color: black;">pformat</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">NOT_FOUND</span><span style="color: black;">&#41;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> handle_storage<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, command, args, path, environ<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> command == <span style="color: #483d8b;">'info'</span>:
      <span style="color: #ff7700;font-weight:bold;">if</span> args == <span style="color: #483d8b;">'collections'</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> JsonResponse<span style="color: black;">&#40;</span>json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'timestamps'</span>, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> command == <span style="color: #483d8b;">'storage'</span>:
      <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'/'</span> <span style="color: #ff7700;font-weight:bold;">in</span> args:
        col, key = args.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span>
      <span style="color: #ff7700;font-weight:bold;">else</span>:
        col, key = args, <span style="color: #008000;">None</span>
      <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> key: <span style="color: #808080; font-style: italic;"># list output requested</span>
          opts = <span style="color: #dc143c;">urlparse</span>.<span style="color: black;">parse_qs</span><span style="color: black;">&#40;</span>environ<span style="color: black;">&#91;</span><span style="color: #483d8b;">'QUERY_STRING'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
          <span style="color: #dc143c;">test</span> = <span style="color: #008000;">self</span>.<span style="color: black;">opts_test</span><span style="color: black;">&#40;</span>opts<span style="color: black;">&#41;</span>
          result = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
          <span style="color: #ff7700;font-weight:bold;">for</span> val <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span>col, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">itervalues</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
            val = json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>val<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">test</span><span style="color: black;">&#40;</span>val.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'modified'</span>, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
              result.<span style="color: black;">append</span><span style="color: black;">&#40;</span>val<span style="color: black;">&#41;</span>
          result = <span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>result,
                          key=<span style="color: #ff7700;font-weight:bold;">lambda</span> val: <span style="color: black;">&#40;</span>val.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'sortindex'</span><span style="color: black;">&#41;</span>,
                                           val.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'modified'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
                          reverse=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
          <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'limit'</span> <span style="color: #ff7700;font-weight:bold;">in</span> opts:
            result = result<span style="color: black;">&#91;</span>:<span style="color: #008000;">int</span><span style="color: black;">&#40;</span>opts<span style="color: black;">&#91;</span><span style="color: #483d8b;">'limit'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
          <span style="color: #dc143c;">logging</span>.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'result set len = %d'</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>result<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
          <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'application/newlines'</span> <span style="color: #ff7700;font-weight:bold;">in</span> environ.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'HTTP_ACCEPT'</span>, <span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>:
            value = <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>val<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> val <span style="color: #ff7700;font-weight:bold;">in</span> result<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">OK</span>, value,
                                content_type=<span style="color: #483d8b;">'application/text'</span><span style="color: black;">&#41;</span>
          <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> JsonResponse<span style="color: black;">&#40;</span>json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>result<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
          <span style="color: #ff7700;font-weight:bold;">return</span> JsonResponse<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: #dc143c;">collections</span>.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span>col, <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>key<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
      <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> key: <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">NOT_FOUND</span>, <span style="color: #483d8b;">'&quot;record not found&quot;'</span>,
                            content_type=<span style="color: #483d8b;">'application/json'</span><span style="color: black;">&#41;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> __process_handler<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, handler<span style="color: black;">&#41;</span>:
    path = <span style="color: #008000;">self</span>.<span style="color: black;">request</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'PATH_INFO'</span><span style="color: black;">&#93;</span>
    response = handler<span style="color: black;">&#40;</span>path, <span style="color: #008000;">self</span>.<span style="color: black;">request</span>.<span style="color: black;">environ</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> response
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__call__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, environ, start_response<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Main WSGI application method&quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #008000;">self</span>.<span style="color: black;">request</span> = HttpRequest<span style="color: black;">&#40;</span>environ<span style="color: black;">&#41;</span>
    method = <span style="color: #483d8b;">'_handle_%s'</span> <span style="color: #66cc66;">%</span> environ<span style="color: black;">&#91;</span><span style="color: #483d8b;">'REQUEST_METHOD'</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># See if we have a method called 'handle_METHOD', where</span>
    <span style="color: #808080; font-style: italic;"># METHOD is the name of the HTTP method to call.  If we do,</span>
    <span style="color: #808080; font-style: italic;"># then call it.</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>:
      handler = <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>
      response = <span style="color: #008000;">self</span>.__process_handler<span style="color: black;">&#40;</span>handler<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
      response = HttpResponse<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">METHOD_NOT_ALLOWED</span>,
                              <span style="color: #483d8b;">'Method %s is not yet implemented.'</span> <span style="color: #66cc66;">%</span> method<span style="color: black;">&#41;</span>
&nbsp;
    start_response<span style="color: black;">&#40;</span>response.<span style="color: black;">status</span>, response.<span style="color: black;">headers</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>response.<span style="color: black;">content</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> NoLogging<span style="color: black;">&#40;</span>wsgiref.<span style="color: black;">simple_server</span>.<span style="color: black;">WSGIRequestHandler</span><span style="color: black;">&#41;</span>:
  <span style="color: #ff7700;font-weight:bold;">def</span> log_request<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
  <span style="color: #dc143c;">socket</span>.<span style="color: black;">setdefaulttimeout</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">300</span><span style="color: black;">&#41;</span>
  <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'-v'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">sys</span>.<span style="color: black;">argv</span>:
    <span style="color: #dc143c;">logging</span>.<span style="color: black;">basicConfig</span><span style="color: black;">&#40;</span>level=<span style="color: #dc143c;">logging</span>.<span style="color: black;">DEBUG</span><span style="color: black;">&#41;</span>
    handler_class = wsgiref.<span style="color: black;">simple_server</span>.<span style="color: black;">WSGIRequestHandler</span>
  <span style="color: #ff7700;font-weight:bold;">else</span>:
    <span style="color: #dc143c;">logging</span>.<span style="color: black;">basicConfig</span><span style="color: black;">&#40;</span>level=<span style="color: #dc143c;">logging</span>.<span style="color: black;">ERROR</span><span style="color: black;">&#41;</span>
    handler_class = NoLogging
  <span style="color: #dc143c;">logging</span>.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Serving on port %d.'</span> <span style="color: #66cc66;">%</span> DEFAULT_PORT<span style="color: black;">&#41;</span>
  app = WeaveApp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
  httpd = wsgiref.<span style="color: black;">simple_server</span>.<span style="color: black;">make_server</span><span style="color: black;">&#40;</span>BIND_IP, DEFAULT_PORT, app,
                                            handler_class=handler_class<span style="color: black;">&#41;</span>
  httpd.<span style="color: black;">serve_forever</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Here is the relevant fragment from my nginx configuration file:</p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;"># Mozilla Weave
location /0.5 {
  auth_basic            &quot;Weave&quot;;
  auth_basic_user_file  /home/majid/web/conf/htpasswd.weave;
  proxy_pass            http://localhost:8000;
  proxy_set_header      Host $http_host;
}
location /1.0 {
  auth_basic            &quot;Weave&quot;;
  auth_basic_user_file  /home/majid/web/conf/htpasswd.weave;
  proxy_pass            http://localhost:8000;
  proxy_set_header      Host $http_host;
}
location /1/ {
  auth_basic            &quot;Weave&quot;;
  auth_basic_user_file  /home/majid/web/conf/htpasswd.weave;
  proxy_pass            http://localhost:8000;
  proxy_set_header      Host $http_host;
}</pre></div></div>

<p>This code is hereby released into the public domain. You are welcome to use it as you wish. Just keep in mind that since it is reverse-engineered, it may well break with future releases of the Weave extension, or if Mozilla changes the server protocol.</p>
<p>Update (2009-10-03):</p>
<p>I implemented some minor changes for compatibility with Weave 0.7. The diff with the previous version is as follows:</p>
<pre>--- weave_server.py~	Thu Sep  3 17:46:44 2009
+++ weave_server.py	Sat Oct  3 02:59:19 2009
@@ -65,8 +65,7 @@
     command, args = path.split('/', 4)[3:]
     return command, args

-  def opts_test(self, environ):
-    opts = urlparse.parse_qs(environ['QUERY_STRING'])
+  def opts_test(self, opts):
     if 'older' in opts:
       return float(opts['older'][0]).__ge__
     elif 'newer' in opts:
@@ -92,7 +91,7 @@
   def _handle_POST(self, path, environ):
     try:
       status = httplib.NOT_FOUND
-      if path.startswith('/0.5/') and path.endswith('/'):
+      if path.startswith('/0.5/'):
         command, args = self.parse_url(path)
         col = args.split('/')[0]
         vals = json.loads(self.request.contents)
@@ -113,7 +112,8 @@
       command, args = self.parse_url(path)
       col, key = args.split('/', 1)
       if not key:
-        test = self.opts_test(environ)
+        opts = urlparse.parse_qs(environ['QUERY_STRING'])
+        test = self.opts_test(opts)
         col = self.collections.setdefault(col, {})
         for key in col.keys():
           if test(json.loads(col[key]).get('modified', 0)):
@@ -142,10 +142,14 @@
       if args == 'collections':
         return JsonResponse(json.dumps(self.collections.get('timestamps', {})))
     if command == 'storage':
-      col, key = args.split('/')
+      if '/' in args:
+        col, key = args.split('/')
+      else:
+        col, key = args, None
       try:
         if not key: # list output requested
-          test = self.opts_test(environ)
+          opts = urlparse.parse_qs(environ['QUERY_STRING'])
+          test = self.opts_test(opts)
           result = []
           for val in self.collections.setdefault(col, {}).itervalues():
             val = json.loads(val)
@@ -155,6 +159,8 @@
                           key=lambda val: (val.get('sortindex'),
                                            val.get('modified')),
                           reverse=True)
+          if 'limit' in opts:
+            result = result[:int(opts['limit'][0])]
           logging.info('result set len = %d' % len(result))
           if 'application/newlines' in environ.get('HTTP_ACCEPT', ''):
             value = '\n'.join(json.dumps(val) for val in result)</pre>
<p>Update (2009-11-17):</p>
<p>Weave 1.0b1 uses 1.0 as the protocol version string instead of 0.5 but is otherwise unchanged. I updated the script and <tt>nginx</tt> configuration accordingly.</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/just-enough-weave/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Olympus E-P1 hands-on impressions</title>
		<link>http://majid.info/blog/olympus-e-p1-hands-on-impressions/</link>
		<comments>http://majid.info/blog/olympus-e-p1-hands-on-impressions/#comments</comments>
		<pubDate>Sat, 18 Jul 2009 08:21:35 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Photo]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2009/07/18-1.html</guid>
		<description><![CDATA[I had the opportunity to handle an Olympus E-P1 camera at Keeble &#38; Shuchat in Palo Alto. There has been quite a bit of excitement on sites like Rangefinder Forum and many were expecting this to be the first pocketable &#8230; <a href="http://majid.info/blog/olympus-e-p1-hands-on-impressions/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I had the opportunity to handle an <a href="http://www.olympusamerica.com/cpg_section/product.asp?product=1461">Olympus E-P1</a> camera at <a href="http://www.kspphoto.com/">Keeble &amp; Shuchat</a> in Palo Alto. There has been quite a bit of excitement on sites like <a href="http://www.rangefinderforum.com/">Rangefinder Forum</a> and many were  expecting this to be the first pocketable camera that could compete with SLRs in image quality.</p>
<p>The Sigma DP1 and DP2 were actually the first cameras with large sensors and reasonable pixel counts, bucking the marketing-driven trend towards <a href="/blog/the-megapixel-myth-a-pixel-too-far/">too many pixels</a> squeezed onto too small a sensor chip, with horrible noise as the result. I own both, and their image quality is indeed stunning, but they have one Achilles&#8217; heel &mdash; speed, or the lack thereof.</p>
<p>The E-P1 is very compact, almost the same size with the 17mm as the Sigma DP2 (some photos released suggested it was closer to the Leica M8). The build quality is fine, and it is nowhere near as heavy as some early users suggested it was. They probably compared it to a plastic fantastic compact rather than a more substantial camera like a Leica or a DSLR.</p>
<p>I was surprised to find the 17mm AF hunted quite a bit, overshooting and then backtracking. Oddly, it did this even on the next shot when the lens was already in focus. I don&#8217;t know if this is specific to the 17mm lens, but it is certainly not encouraging.</p>
<p>From my test shots, I was also distinctly unimpressed by the optical quality of the lens, or the noise performance at ISO 1600. The Four-Thirds and Micro Four Thirds formats are hobbled by sensors one half the size of the APS-C used in most entry-level DSLRs, with predictably higher levels of noise and limited dynamic range. I had to go back to 2003 and my then Canon EOS 10D to find similar levels of noise. The Canon Rebel XT was definitely superior in high-ISO performance, let alone current SLRs. Olympus fanboys seem to be in denial about the limitations of Four-Thirds sensors, but you cannot fight against physics and expect to win.</p>
<p>The other disappointing thing about the 17mm lens is that it is not particularly sharp, specially for a prime lens of relatively modest maximum aperture. The pictures were nowhere near as crisp as the lovely Sigma lenses on the DP1 and DP2. This is all the more a let-down as Olympus was renowned for the quality of its miniaturized prime lenses in the days of the ground-breaking OM system. I wasn&#8217;t expecting Pentax SMC Limited pancake lens levels of performance (we are talking of a lens one third the price, after all), but there is no point in having 12 megapixels (at least 6 too far in my book) if the lens can&#8217;t actually exploit them.</p>
<p>I had preordered an E-P1 with the 17mm kit lens and viewfinder from  Amazon. After handling the E-P1 and taking a few test shots, I canceled my order.</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/olympus-e-p1-hands-on-impressions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fuji GF670 first impressions</title>
		<link>http://majid.info/blog/fuji-gf670-first-impressions/</link>
		<comments>http://majid.info/blog/fuji-gf670-first-impressions/#comments</comments>
		<pubDate>Fri, 29 May 2009 08:23:26 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Photo]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2009/05/29-1.html</guid>
		<description><![CDATA[I just received my Fuji GF670 from Dirk R&#246;sler at Japan Exposures. This is a folding medium-format rangefinder camera, an anachronism in many respects, but I regret not getting a G690 when they were still made and since this is &#8230; <a href="http://majid.info/blog/fuji-gf670-first-impressions/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.majid.info/mylos/galleries/gf670/gf670-07_thm.jpg" width="200" height="175" alt="Fuji GF670" style="margin-left: 10px; margin-bottom: 50px;" align="right">I just received my <a href="http://www.japanexposures.com/shop/product_info.php?cPath=31&amp;products_id=259">Fuji GF670</a> from Dirk R&ouml;sler at Japan Exposures. This is a folding medium-format rangefinder camera, an anachronism in many respects, but I regret not getting a G690 when they were still made and since this is a limited edition (apparently quite a popular one at that), I went ahead. I have not yet shot a roll, but here are my first impressions:</p>
<ul>
<li>The unfolding mechanism is a bit finnicky. You have to be careful to get the front standard aligned with the film plane. Once deployed it seems fairly stable.  Folding it back is also quite tricky.</li>
<li>The meter indicator LEDs and controls are very reminiscent of the Epson R-D1, not surprising since both are actually made by Cosina.</li>
<li>The leaf shutter is amazingly quiet. It makes a Leica sound like a clunker in comparison.</li>
<li>The camera is quite light for MF, it feels lighter than a R-D1 (even though it weighs nearly twice as much) and is not that much larger.</li>
<li>It does not exude quality like the Fuji-manufactured TX-2 (Hasselblad XPan II).</li>
<li>The rangefinder patch is bright and clear. The RF base length is very short as in a VC Bessa, and will probably not be as precise as a Leica, XPan or Zeiss Ikon.</li>
<li>The film loading mechanism is very easy to use, and built as well as other Fuji MF cameras such as the G617.</li>
<li>You have to remember to reset the lens to infinity focus in order to fold it.</li>
<li>You get a choice of 6&#215;6 and 6&#215;7, 120 and 220.</li>
<li>The optional case is a snug fit. I wish it included a belt loop.</li>
</ul>
<p>In grand old techno-fetishistic tradition, I put up an <a href="/blog/gf670/">unboxing gallery</a>.</p>
<p>Update (2009-08-27):</p>
<p>I have finally uploaded a <a href="/blog/gf670_samples/">gallery</a> of my first test roll from the camera. The lens&#8217; optical quality is outstanding, unlike most older folders (well, apart from the Plaubel Makina, of course).</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/fuji-gf670-first-impressions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Anthony&#8217;s Cookies grand opening</title>
		<link>http://majid.info/blog/anthonys-cookies-grand-opening/</link>
		<comments>http://majid.info/blog/anthonys-cookies-grand-opening/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 01:44:24 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Food]]></category>
		<category><![CDATA[San Francisco]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2009/04/25-1.html</guid>
		<description><![CDATA[Another gourmet treats shop joined the burgeoning scene in the Mission. Anthony&#8217;s Cookies opened today to a line that stretched around the corner. As one of the officials present said, it takes courage to start a business in this economic &#8230; <a href="http://majid.info/blog/anthonys-cookies-grand-opening/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://majid.info/blog/wp-content/uploads/2009/04/anthony1.jpg" width="500" height="500" alt="Anthony"></center>
<p>Another gourmet treats shop joined the burgeoning scene in the Mission. <a href="http://www.anthonyscookies.com/home.html">Anthony&#8217;s Cookies</a> opened today to a line that stretched around the corner.</p>
<p> <center><img src="http://majid.info/blog/wp-content/uploads/2009/04/anthony2.jpg" width="500" height="333" alt="Opening"></center>
<p>As one of the officials present said, it takes courage to start a business in this economic climate. Specially in as business-hostile a city as San Francisco, if I may add.</p>
<p> <center><img src="http://majid.info/blog/wp-content/uploads/2009/04/anthony3.jpg" width="500" height="333" alt="Anthony"></center>
<p>Inside the store was a buzzing hive of activity, with the eponymous proprietor busy preparing batches of free cookies for the awaiting hordes. At $5 for a half dozen, these cookies are a steal. I tried the double chocolate chip, it came fresh from the oven and had a strong chocolate aroma and the right texture. All in all, a great addition to a neighborhood that already has more than its share of good places to indulge a sweet tooth. I added him to my <a href="http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;msa=0&amp;msid=100646927091773036507.00045f79c16c3a25965f8&amp;z=13">Google map</a> of recommended bakeries, ice cream parlors and sweet shops in San Francisco.</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/anthonys-cookies-grand-opening/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Garbage-collecting your Mac OS X Address Book</title>
		<link>http://majid.info/blog/garbage-collecting-your-mac-os-x-address-book/</link>
		<comments>http://majid.info/blog/garbage-collecting-your-mac-os-x-address-book/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 23:48:36 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2009/03/27-1.html</guid>
		<description><![CDATA[After years of Outlook and Palm synchronization, when I fully switched over to the Mac, I moved my contacts database over to Mac OS X&#8217;s Address Book (painfully due to Outlook&#8217;s roach motel tendencies, but that&#8217;s another story). For the &#8230; <a href="http://majid.info/blog/garbage-collecting-your-mac-os-x-address-book/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>After years of Outlook and Palm synchronization, when I fully switched over to the Mac, I moved my contacts database over to Mac OS X&#8217;s Address Book (painfully due to Outlook&#8217;s roach motel tendencies, but that&#8217;s another story). For the most part I am satisfied, its data model is far more powerful than Outlook&#8217;s, and most Mac apps feature excellent Address Book integration. I can call someone using Skype just by right-clicking on a phone number, for instance.</p>
<p>I just noticed, however, that my scripted Address Book backups were pushing the bounds of the reasonable: over 60MB zipped. For a mere 357 contacts, that seems a tad excessive. Upon further inspection, I realized my Address Book directory <tt>~/Library/Application Support/AddressBook</tt> was pushing 152MB, the bulk of it in the <tt>Images</tt> subdirectory.</p>
<p>It turns out there are two causes for this problem:</p>
<ol>
<li>When you drag and drop an image for a contact, then crop it, Address Book keeps the full-size image around, presumably in case you want to change the crop later. In most cases this is unnecessary and wastes space.</li>
<li>Address Book does not seem to remove the images for a contact when you delete it. Worse, those images get carried over into manual backups and thus backing up, blowing away your Address Book directory and restoring from backup will not get rid of the cruft.</li>
</ol>
<p>I wrote the short shell script below to back up the AB directory, extract the list of contacts and delete any image that fits in the two categories above. This took me down to a much more reasonable 11MB. You can download the <a href="http://majid.info/blog/wp-content/uploads/2009/03/ab_clean.zip">zipped script here</a>. Disclaimer: I tried my best to make this as generic as possible, but I cannot be held responsible if running this script causes you to lose data, so I would advise you to perform your own backup prior to running it.</p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">&nbsp;
#!/bin/sh
backup=$HOME/ab_clean_backup.$$
in_ab=$backup/in_ab
all=$backup/all
datadir=&quot;$HOME/Library/Application Support/AddressBook&quot;
db=`echo &quot;$datadir&quot;/*.abcddb`
&nbsp;
exit_ab() {
  echo killing AddressBook
  ps -u `whoami` | grep &quot;Address Book&quot; | grep /Applications | awk '{print $2}'|xargs -n 1 kill -9
}
&nbsp;
backup_ab() {
  echo &quot;Backing up address book directory $datadir to backup $backup&quot;
  rm -rf  $backup &gt; /dev/null 2&gt;&amp;1
  mkdir $backup
  ditto &quot;$datadir&quot; &quot;$backup&quot;
}
&nbsp;
remove_old() {
  echo extract list of contacts in AB from SQLite
  sqlite3 &quot;$db&quot; &quot;select zuniqueid from zabcdrecord&quot;|cut -d: -f 1|sort &gt; $in_ab
&nbsp;
  cd &quot;$datadir&quot;
  cd Images
&nbsp;
  # comment out the next two lines if you want to keep full-size originals
  echo removing full-scale images
  rm -f *.jpeg
&nbsp;
  echo finding all the images
  ls -1|grep -v '\.jpeg$'|sort &gt; $all
&nbsp;
  echo removing images with no associated AB record
  comm -13 $in_ab $all | xargs rm
}
&nbsp;
exit_ab
backup_ab
remove_old</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/garbage-collecting-your-mac-os-x-address-book/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nehalem Mac Pro first impressions</title>
		<link>http://majid.info/blog/nehalem-mac-pro-first-impressions/</link>
		<comments>http://majid.info/blog/nehalem-mac-pro-first-impressions/#comments</comments>
		<pubDate>Wed, 18 Mar 2009 08:00:25 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2009/03/18-1.html</guid>
		<description><![CDATA[Some people use laptops as their primary computing environment. I am not one of them. Desktop replacement laptops like the MacBook Pro are heavy, and truly portable ones like my MacBook Air are too limited. Even the desktop replacement ones &#8230; <a href="http://majid.info/blog/nehalem-mac-pro-first-impressions/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Some people use laptops as their primary computing environment. I am not one of them. Desktop replacement laptops like the MacBook Pro are heavy, and truly portable ones like my MacBook Air are too limited. Even the desktop replacement ones have limited expandability, slow drives, poor screens, lousy keyboards. My workhorse for the last 5 years was a dual 2GHz PowerMac G5. I am surprised I kept it so long, but I guess that says something about the durability of Macs and how you are not required to go on the hadware upgrade treadmill with each release of the OS. To paraphrase Borges, each increasingly bloated version of Windows makes you regret the previous one. I am also surprised at how much residual value the G5 has kept on eBay.</p>
<p>That said, the G5 was showing its age. Stitching panoramas made from 22MP Canon 5DmkII frames in AutoPano Pro is glacially slow, for instance. I was not willing to switch to the Mac Pro until today because the archaic shared bus on previous Intel chips is a severe bottleneck on multi-processor and multicore performance, unlike the switched interconnect used by PowerPC G5 and AMD Opteron processors, both of which claim descent from the DEC Alpha, the greatest CPU architecture ever designed. The new Xeon 3500 and 5500 Mac Pros use Intel&#8217;s new <a href="http://arstechnica.com/hardware/news/2008/04/what-you-need-to-know-about-nehalem.ars">Nehalem microarchitecture</a>, which finally does away with the shared bus in favor of a switched interconnect called QuickPath and on-chip memory controllers (i.e. Intel cribbed AMD&#8217;s Opteron innovations).</p>
<p>I splurged on the top of the line Mac Pro, with eight 2.93GHz cores, each capable of running two threads simultaneously, and 8GB of RAM. The standard hard drive options were completely lackluster, so I replaced the measly 660GB boot drive with an enterprise-class <a href="http://www.intel.com/design/flash/nand/extreme/index.htm">Intel X25-E</a> SSD. Unfortunately, at 32GB it is just enough to host the OS and applications, so I complemented it with a quiet, power-efficient yet fast 1TB Samsung SpinPoint F1 drive (there is a WD 2TB drive, but it is a slow 5400rpm, and the 1.5TB Seagate drive has well-publicized reliability problems, even if Seagate did the honorable thing unlike IBM with its defective Deathstars).</p>
<p>I originally planned on using the build-to-order ATI Radeon HD 4870 video card upgrade, but found out the hard way it is incompatible with my <a href="/blog/the-value-of-over-the-counter-service/">HP LP3065</a> monitor (more below) and had to downgrade back to the nVidia GeForce GT 120. It would have been nice to use BootCamp for games and retire my gaming PC, but I guess that will have to wait. The GT120 is faster than the 8800GTS in the Windows box, in any case.</p>
<p>In no particular order, here are my first impressions:</p>
<ul>
<li>The &#8220;cheese grater&#8221; case is the same size as the G5, but feels lighter.</li>
<li>The DVD-burner drive tray feels incredibly flimsy.</li>
<li>Boot times are ridiculously fast. Once you&#8217;ve experienced SSDs as I originally did with the MacBook Air, there is no going back to spinning rust.</li>
<li>I have plenty of Firewire 800 to 400 cables for my FW400 devices (Epson R1800, Nikon Super Coolscan 9000ED, Canon HV20 camcorder) so I will probably not miss the old ports and probably not even need a hub (Firewire 800 hubs are very hard to get).</li>
<li>The inside of the case is a dream to work with. The drive brackets are easy to swap, the PCIe slots have a spring-loaded retention bar that hooks under the back of the card, and the L brackets are held with thumbscrews, making swapping the cards trivial, with no risk of getting a marginal connection from a poorly seated card.</li>
<li>The drive mounting brackets have rubber grommets to dampen vibrations, a nice touch. There also seems to be some sort of contact sensor in the rear, purpose unknown.</li>
<li>There are only two PCIe power connectors, so you can only plug in a single ATI 4870 card even though there are two PCIe x16 slots. The GT 120 does not require PCIe power connectors so you would have to expand capacity with one of these. Considering the GT 120 is barely more expensive than the Mini DisplayPort to Dual-Link DVI adapter cable, it makes more sense to get the extra video card if you have two monitors.</li>
<li>The entire CPU and RAM assembly sits on a daughterboard that can be slid out. This will make upgrading RAM (when the modules stop being back-ordered at Crucial) a breeze.</li>
<li>Built-in Bluetooth means no more flaky USB dongles.</li>
<li>No extras. The G5 included OmniGraffle, OmniOutliner, Quickbooks, Comic Life and a bunch of other apps like Art Director&#8217;s Toolkit. No such frills on the Mac Pro even though it is significantly more expensive even in its base configuration.</li>
<li>The optical out is now 96kHz 24-bit capable, unlike the G5 that was limited to 44kHz 16-bit Red Book audio. I have some lossless 192kHz studio master recordings from <a href="http://www.linnrecords.com/">Linn Records</a>, so I will have to get a USB DAC to get full use out of them. I am not sure why Apple cheaped out on the audio circuitry in a professional workstation that is going to be heavily used by musicians.</li>
<li>The G5 was one of the first desktop machines to have a gigabit Ethernet port. Apple didn&#8217;t seize the opportunity to lead with 10G Ethernet.</li>
<li>The annoying Mini DisplayPort is just as proprietary as ADC, but without the redeeming usability benefits of using a single cable for power, video and USB. DisplayPort makes sense for professional use with high-end monitors like the <a href="http://h10010.www1.hp.com/wwpc/us/en/sm/WF05a/382087-382087-64283-72270-444767-3648397.html">HP Dreamcolor LP2480zx</a> that can actually use 10-bit DACs for ultra-accurate color workflows. There is no mini to regular DisplayPort adapter, unfortunately. Well, the thinness of the cable is a redeeming feature. Apple has always paid attention to using premium ultra-flexible cables everywhere  from the power cord to Firewire.</li>
<li>Transferring over 800GB of data from the old Mac is utterly tedious, even over Firewire 800 using Target Disk mode on the G5&#8230;</li>
<li>As could be expected, the Mac Pro wipes the floor with the G5, as <a href="http://db.xbench.com/merge.xhtml?doc1=165177&amp;doc2=354400">measured by Xbench</a>. A more interesting comparison is <a href="http://db.xbench.com/merge.xhtml?doc1=266970&amp;doc2=354400">with the MacBook Air</a>, which also uses a SSD, albeit a slowish one.</li>
</ul>
<p>Note (2009-03-17):</p>
<p>The BTO upgrade ATI Radeon HD 4870 video card I initially ordered  won&#8217;t recognize my HP LP3065 30&#8243; monitor, at least not on the Dual-link DVI port, which essentially renders it useless for me.</p>
<p>Update (2009-03-18):</p>
<p>I went to the Hillsdale Apple Store. The tech was very helpful, but we managed to verify that the ATI Radeon HD 4870 card works fine on an Apple 30&#8243; Cinema Display (via Dual-link DVI) and on a 24&#8243; Cinema LED display (via mini-DisplayPort). The problem is clearly an incompatibility between the ATI Radeon HD 4870 and the HP LP3065.</p>
<p>I am not planning on switching monitors. The HP is probably the best you can get under $3000, and far superior in gamut, ergonomics (tilt/height adjustments) and connectivity (3 Dual-link DVI ports) to the current long-in-the-tooth Apple equivalent, for 2/3 the price. My only option is to downgrade the video card to a nVidia GeForce GT 120. I ordered one from the speedy and reliable folks at <a href="http://www.bhphotovideo.com/">B&amp;H</a> and should get it tomorrow (Apple has it back-ordered for a week).</p>
<p>Update (2009-03-19):</p>
<p>I swapped the ATI 4870 for the nVidia GT120. The new card works with the monitor. Whew!</p>
<p>Update (2009-03-29):</p>
<p>I have just learned disturbing news about racial discrimination at B&amp;H. For the <a href="http://www.rangefinderforum.com/forums/showthread.php?p=1023684#post1023684">reasons I give on RFF</a>, I can no longer recommend shopping there.</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/nehalem-mac-pro-first-impressions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Parallelizing the command-line</title>
		<link>http://majid.info/blog/parallelizing-the-command-line/</link>
		<comments>http://majid.info/blog/parallelizing-the-command-line/#comments</comments>
		<pubDate>Sun, 28 Sep 2008 06:15:11 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2008/09/27-1.html</guid>
		<description><![CDATA[Single-thread processor performance has stalled for a few years now. Intel and AMD have tried to compensate by multiplying cores, but the software world has not risen to the challenge, mostly because the problem is a genuinely hard one. Shell &#8230; <a href="http://majid.info/blog/parallelizing-the-command-line/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Single-thread processor performance has stalled for a few years now. Intel and AMD have tried to compensate by multiplying cores, but the software world has not risen to the challenge, mostly because the problem is a genuinely hard one.</p>
<p>Shell scripts are still usually serial, and increasingly at odds with the multi-core future of computing. Let&#8217;s take a simple task as an example, converting a large collection of images from TIFF to JPEG format using a tool like <a href="http://www.imagemagick.org/">ImageMagick</a>. One approach would be to spawn a <tt>convert</tt> process per input file as follows:</p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">&nbsp;
#!/bin/sh
for file in *.tif; do
  convert $file `echo $file|sed -e 's/.tif$/.jpg/g' &amp;
done</pre></div></div>

<p>This does not work. If you have many TIFF files to convert (what would be the point of parallelizing if that were not the case?), you will fork off too many processes, which will contend for CPU and disk I/O bandwidth, causing massive congestion and degrading performance. What you want is to have only as many concurrent processes as there are cores in your system (possibly adding a few more because a tool like <tt>convert</tt> is not 100% efficient at using CPU power). This way you can tap into the full power of your system without overloading it.</p>
<p>The GNU <tt>xargs</tt> utility gives you that power using its <tt>-P</tt> flag. <tt>xargs</tt> is a UNIX utility that was designed to work around limits on the maximum size of a command line (usually 256 or 512 bytes). Instead of supplying arguments over the command-line, you supply them as the standard input of <tt>xargs</tt>, which then breaks them into manageable chunks and passes them to the utility you specify.</p>
<p>The <tt>-P</tt> flag to GNU <tt>xargs</tt>specifies how many concurrent processes can be running. Some other variants of <tt>xargs</tt> like OS X&#8217;s non-GNU (presumably BSD) <tt>xargs</tt> also support <tt>-P</tt> but not Solaris&#8217;. <tt>xargs</tt> is very easy to script and can provide a significant boost to batch performance. The previous script can be rewritten to use 4 parallel processes:</p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">&nbsp;
#!/bin/sh
CPUS=4
ls *.tif|sed -e 's/.tif$//g'|gxargs -P $CPUS -n 1 -I x convert x.tif x.jpg</pre></div></div>

<p>On my Sun Ultra 40 M2 (2x 1.8GHz AMD Opterons, single-core), I benchmarked this procedure against 920MB of TIFF files. As could be expected, going from 1 to 2 concurrent processes improved throughput dramatically, going from 2 to 3 yielded marginal improvements (<tt>convert</tt> is pretty good at utilizing CPU to the max). Going from 3 to 4 actually degraded performance, presumably due to the kernel overhead of managing the contention.</p>
<p> <center><img alt="benchmark" src="http://majid.info/blog/wp-content/uploads/2008/09/xargs.png" width="584" height="227"></center>
<p>Another utility that is parallelizable is GNU <tt>make</tt> using the <tt>-j</tt> flag. I parallelize as many of my build procedures as possible, but for many open-source packages, the usual <tt>configure</tt> step is not parallelized (because <tt>configure</tt> does not really understand the concept of dependencies). Unfortunately there are too many projects whose makefiles are missing dependencies, causing parallelized makes to fail. In this day and age of Moore&#8217;s law running out of steam as far as single-task performance is concerned, harnessing parallelism using <tt>gxargs -P</tt> or <tt>gmake -j</tt> is no longer a luxury but should be considered a necessity.</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/parallelizing-the-command-line/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Large sensor compact cameras finally on the horizon</title>
		<link>http://majid.info/blog/large-sensor-compact-cameras-finally-on-the-horizon/</link>
		<comments>http://majid.info/blog/large-sensor-compact-cameras-finally-on-the-horizon/#comments</comments>
		<pubDate>Sat, 30 Aug 2008 18:37:21 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Photo]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2008/08/30-1.html</guid>
		<description><![CDATA[I have stated on the record that my dream camera is a digital Contax T3 with an APS-C size sensor (or larger). Sigma launched the DP1, the first large-sensor compact this year, but it is a flawed camera, very sluggish, &#8230; <a href="http://majid.info/blog/large-sensor-compact-cameras-finally-on-the-horizon/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I have <a href="/blog/the-megapixel-myth-a-pixel-too-far/">stated on the record</a> that my dream camera is a digital Contax T3 with an APS-C size sensor (or larger). Sigma launched the <a href="http://sigma-dp1.com/">DP1</a>, the first large-sensor compact this year, but it is a flawed camera, very sluggish, with a slow f/4 lens, and its Foveon sensor tops out at ISO 800, making it in practice a less capable low-light camera than my <a href="http://www.dpreview.com/reviews/fujifilmf31fd/">Fuji F31fd</a>.</p>
<p>A few weeks ago, Olympus and Panasonic announced the <a href="http://www.dpreview.com/news/0808/08080501microfourthirds.asp">Micro Four Thirds</a> specification, which would allow for interchangeable-lens compact cameras with a larger sensor than the nasty tiny and noisy ones used on most compacts. Unfortunately it seems the whole misguided Four Thirds effort is destined to flounder, just as APS did compared to 35mm, despite the undeniable convenience. The 18&#215;13.5mm sensor size has almost half the area of an APS-C sensor and all Four Thirds camera made so far have predictably poor low-light performance.</p>
<p>In a much more promising development, Samsung <a href="http://www.amateurphotographer.co.uk/news/new_interchangeable_lens_system_compact_digital_camera_system_on_the_way_news_266661.html?aff=rss">announced today</a> that since it is finding it very hard to dislodge Canon and Nikon from their top position in DSLRs or even make a dent, they are going to create an entire new segment of professional quality compact cameras using the same APS-C sensors as their DSLRs, and due for 2010. Samsung uses the Pentax lens mount for its DSLRs, and has a long established relationship with Schneider Kreuznach. Pentax makes some very nice pancake lenses that combine high optical quality with small size. The only other company is Olympus, but the 25mm f/2 is saddled with the aforementioned Four Thirds sensor with all the limitations that entails.</p>
<p>At the same time, Thom Hogan has echoed rumors of an APS-C size Coolpix compact from Nikon. It looks like the big camera manufacturers can no longer afford to ignore the pent-up demand for this category, as demonstrated by the brisk sales of the DP1 (No. 49 on Amazon&#8217;s Digital SLR chart).</p>
<p>Update (2010-10-06):</p>
<p>There is now a wide variety of large-sensor compacts, including models with interchangeable lenses:</p>
<ul>
<li>Sigma DP1, DP1s, DP2, DP2s and DP2x: wonderful optics, compact, great image quality, mediocre high-ISO performance, very slow AF and user interface</li>
<li>Olympus EP-1, EP-2 and E-PL: cute design, sensor stabilization, poor ISO performance, slow AF, so-so optics unworthy of the Zuiko legacy, but you can use Panasonic&#8217;s lenses on them)</li>
<li>Panasonic GF1: great design, solid but heavy, mediocre ISO performance, very fast AF, great optics</li>
<li>Leica X1: great optics, best high-ISO performance, excellent user interface, very compact and light, slow AF, no video, very expensive). The camera I carry with me every day in my jacket pocket.</li>
<li>Sony NEX-3 and NEX-5: great high-ISO performance, poor user interface, very compact, awkward 24mm-e focal length if you want a compact lens. Made by an evil company that should be boycotted.</li>
<li>Samsung NX100: disappointing high-ISO performance for an APS-C sensor, optical quality a question mark.</li>
<li>Fuji X100: bulky, innovative viewfinder design, questionable user interface in the prototype, potential for greatness, but we will have to wait for the final production models.</li>
</ul>
<p>Canon and Nikon are late to the party, and risk being marginalized if they continue to ignore market demand.</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/large-sensor-compact-cameras-finally-on-the-horizon/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>r n m restaurant</title>
		<link>http://majid.info/blog/r-n-m-restaurant/</link>
		<comments>http://majid.info/blog/r-n-m-restaurant/#comments</comments>
		<pubDate>Sun, 13 Jul 2008 07:39:19 +0000</pubDate>
		<dc:creator>majid</dc:creator>
				<category><![CDATA[Food]]></category>
		<category><![CDATA[San Francisco]]></category>
		<category><![CDATA[Mylos]]></category>

		<guid isPermaLink="false">http://www.majid.info/mylos/weblog/2008/07/12-1.html</guid>
		<description><![CDATA[I have just eaten what is hands-down my best meal of the year at r n m restaurant (their capitalization, not mine), on Haight &#38; Steiner in the Duboce Park/Lower Haight district of San Francisco (not to be confused with &#8230; <a href="http://majid.info/blog/r-n-m-restaurant/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.rnmrestaurant.com/entrance1.jpg" alt="rnm" style="margin-left: 10px; margin-bottom: 50px;" align="right" height="306" width="400">I have just eaten what is hands-down my best meal of the year at <a href="http://www.rnmrestaurant.com/">r n m restaurant</a> (their capitalization, not mine), on Haight &amp; Steiner in the Duboce Park/Lower Haight district of San Francisco (not to be confused with the formerly raffish and now utterly commercialized Haight-Ashbury).</p>
<p>The restaurant is named after the chef-owner&#8217;s father, Robert Miner, a co-founder of Oracle. The food was so good I am almost ready to forgive Oracle for their sleazy extortion tactics&#8230;</p>
<p>I started with the <em>Parisian style tuna tartare with waffle chips, microgreens and a quail egg</em>, a very classic dish (and one too often botched by careless chefs), given a little pep with a slight acidity. It was followed by an absolutely outstanding <em>pan-roasted local halibut on ricotta gnocchi with asparagus and morel mushroom ragout, meyer lemon vinaigrette and m&acirc;che</em>. The halibut was crisp outside, flaky inside. The rago&ucirc;t was simply wonderful, a deep, rich and tangy broth, also slightly acidulated, with a generous helping of precious black morels. To top it off, the dessert, a <em>Peach and cherry crisp with home-made blueberry gelato</em> combined two of my favorite summer fruit in an unbeatable combination.</p>
<p>Be advised the parking situation in that neighborhood is particularly nightmarish, even by SF standards. If I had realized they offer valet parking, I wouldn&#8217;t have had to park halt a mile away (after seeking a place in vain for nearly half an hour).</p>
]]></content:encoded>
			<wfw:commentRss>http://majid.info/blog/r-n-m-restaurant/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

