<?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>Oliver Roup's Blog &#187; Code</title>
	<atom:link href="http://blog.oroup.com/category/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.oroup.com</link>
	<description>Technology &#124; Politics &#124; Culture</description>
	<lastBuildDate>Mon, 29 Mar 2010 23:36:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Keyboard modified clicks</title>
		<link>http://blog.oroup.com/2010/03/29/keyboard-modified-clicks/</link>
		<comments>http://blog.oroup.com/2010/03/29/keyboard-modified-clicks/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 23:36:03 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/?p=1428</guid>
		<description><![CDATA[In case you&#8217;re ever wondering, here is a full list of the &#8220;key modified clicks&#8221; that the major browsers look for: (Note that on Windows, &#8220;cmd&#8221; is &#8220;ctrl&#8221;) Chrome, Firefox: shift: new active window cmd: new tab cmd-shift: new active tab Safari: cmd: new tab cmd-shift: new active tab cmd-opt: new window cmd-opt-shift: new active window IE: [...]]]></description>
			<content:encoded><![CDATA[<p>In case you&#8217;re ever wondering, here is a full list of the &#8220;key modified clicks&#8221; that the major browsers look for:</p>
<p>(Note that on Windows, &#8220;cmd&#8221; is &#8220;ctrl&#8221;)</p>
<p>Chrome, Firefox:<br />
shift: new active window<br />
cmd: new tab<br />
cmd-shift: new active tab</p>
<p>Safari:<br />
cmd: new tab<br />
cmd-shift: new active tab<br />
cmd-opt: new window<br />
cmd-opt-shift: new active window</p>
<p>IE:<br />
shift: new active window<br />
ctrl-shift: new active tab</p>
<p>Note that you also need to deal with right clicks and &#8220;open in new window&#8221;, &#8220;open in new tab&#8221;, etc&#8230;.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2010/03/29/keyboard-modified-clicks/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wow Google Spreadsheets</title>
		<link>http://blog.oroup.com/2008/07/03/wow-google-spreadsheets/</link>
		<comments>http://blog.oroup.com/2008/07/03/wow-google-spreadsheets/#comments</comments>
		<pubDate>Thu, 03 Jul 2008 16:54:55 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/?p=43</guid>
		<description><![CDATA[I&#8217;ve long been a fan of Google Spreadsheet. Like all disruptive technologies, it doesn&#8217;t meet the needs of most customers of the incumbent product, Excel. I&#8217;m no banker, but even my relatively neophyte hands keep trying to hit F4 to lock a cell reference or hit F2 to edit a cell. I miss being able [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve long been a fan of Google Spreadsheet. Like all disruptive technologies, it doesn&#8217;t meet the needs of most customers of the incumbent product, Excel. I&#8217;m no banker, but even my relatively neophyte hands keep trying to hit F4 to lock a cell reference or hit F2 to edit a cell. I miss being able to right click to format a cell, the lag time of javascript sometimes annoys the crap out of me, etc&#8230; I would not try to convince a Wall Street number jockey to switch from Excel just yet. No way.</p>
<p>BUT, also like all disruptive technologies Google Spreadsheet is quietly getting good at things that Excel can only dream of. Since it launched, Google Spreadsheet has had great sharing and concurrent editing capabilities. A team at school used a shared Google Spreadsheet as a &#8220;factory information system&#8221; in a simulated factory exercise and it was amazingly powerful.</p>
<p>More recently, Google has added amazing data extraction techniques. Put =GoogleFinance(&#8220;Oil&#8221;, &#8220;Price&#8221;) in a cell and you&#8217;ll get the price of oil updated in realtime. The following will pull all the headlines off Techmeme: <span>=</span><span>importxml(&#8220;http://www.techmeme.com&#8221;, &#8220;/html/body/div[2]/div/div[4]/div/div[2]/div/div/div/strong/a&#8221;)</span></p>
<p>There are also functions for trolling arbitrary HTML, for parsing RSS and Atom feeds and for importing CSS feeds.</p>
<p>Where the mind really starts to boggle is when you think about how every cell in every google spreadsheet effectively has an URL. So it should be almost as easy to publish from your sheet as it is to pull in from somebody else&#8217;s. Suddenly, there are network effects for spreadsheets, where your work can leverage off the work of others. This ability to ref a cell in someone else&#8217;s sheet doesn&#8217;t seem to be enabled just yet, but I can&#8217;t imagine Google isn&#8217;t working on it. I&#8217;m sure there are some issues around permissioning and detection of dependency loops.</p>
<p>Throw in a little work on keyboard shortcuts and a little Google Gears magic to make the app more responsive and workable offline and Excel will be starting to feel the heat&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2008/07/03/wow-google-spreadsheets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PicasaWeb Downloader</title>
		<link>http://blog.oroup.com/2008/05/20/picasaweb-downloader/</link>
		<comments>http://blog.oroup.com/2008/05/20/picasaweb-downloader/#comments</comments>
		<pubDate>Tue, 20 May 2008 10:55:29 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/?p=39</guid>
		<description><![CDATA[In the genuinely useful software dept., here is a little app written in C# (source included!) that will download an entire google web album. Great for grabbing copies of all of your friends photos.]]></description>
			<content:encoded><![CDATA[<p>In the genuinely useful software dept., <a href="http://www.tomergabel.com/PicasaWeb+Downloader.aspx">here</a> is a little app written in C# (source included!) that will download an entire google web album. Great for grabbing copies of all of your friends photos.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2008/05/20/picasaweb-downloader/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Theme weirdness</title>
		<link>http://blog.oroup.com/2008/01/13/theme-weirdness/</link>
		<comments>http://blog.oroup.com/2008/01/13/theme-weirdness/#comments</comments>
		<pubDate>Mon, 14 Jan 2008 06:32:58 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/2008/01/13/theme-weirdness/</guid>
		<description><![CDATA[I upgraded WordPress to the latest version and my theme seemed to be interacting poorly with the new Schema. So I&#8217;ve reverted to the default theme and I&#8217;ll find a new one I like at some point soon.]]></description>
			<content:encoded><![CDATA[<p>I upgraded WordPress to the latest version and my theme seemed to be interacting poorly with the new Schema. So I&#8217;ve reverted to the default theme and I&#8217;ll find a new one I like at some point soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2008/01/13/theme-weirdness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Computing distances with Lat/Lon</title>
		<link>http://blog.oroup.com/2007/01/14/computing-distances-with-latlon/</link>
		<comments>http://blog.oroup.com/2007/01/14/computing-distances-with-latlon/#comments</comments>
		<pubDate>Sun, 14 Jan 2007 19:45:01 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/2007/01/14/computing-distances-with-latlon/</guid>
		<description><![CDATA[Have you ever wanted to compute distances with latitude and longitude? At first it seems so simple. We all learned the pythagorean theorem in elementary school: d=sqrt((x2 &#8211; x1)^2 + (y2 &#8211; y1)^2) So if we have our two points (x1,y1) and (x2,y2) then we should be able to find (x2-x1,y2-y1) and find the distance [...]]]></description>
			<content:encoded><![CDATA[<p>Have you ever wanted to compute distances with latitude and longitude? At first it seems so simple. We all learned the pythagorean theorem in elementary school:<br />
d=sqrt((x2 &#8211; x1)^2 + (y2 &#8211; y1)^2)<br />
So if we have our two points (x1,y1) and (x2,y2) then we should be able to find (x2-x1,y2-y1) and find the distance using the Pythagorean theorem, right? Well, no.</p>
<p>The Pythagorean theorem finds the straight line distance between two points. However, for two points any appreciable distance from each other on earth, trying to get to your destination would involve a lot of digging. Assuming you want to travel overland, you must travel further than the linear distance to account for the curvature of the Earth.</p>
<p>A little further research yields the Haversine Formula which is useful for computing surface distances on a sphere and correctly accounts for points that are very close together:</p>
<p>Haversine Formula (from R.W. Sinnott, &#8220;Virtues of the Haversine&#8221;, Sky and Telescope, vol. 68, no. 2, 1984, p. 159):</p>
<p>dlon = lon2 &#8211; lon1<br />
dlat = lat2 &#8211; lat1<br />
a = sin<sup class="moz-txt-sup">2</sup>(dlat/2) + cos(lat1) * cos(lat2) * sin<sup class="moz-txt-sup">2</sup>(dlon/2)<br />
c = 2 * arcsin(min(1,sqrt(a)))<br />
d = R * c</p>
<p>But what is R, the radius of the Earth?</p>
<p>It turns out the Earth is not a sphere after all. The spinning motion compresses the planet so that the equitorial radius is considerably larger than the polar radius. The shape of the Earth is well approximated by an oblate spheroid with a polar radius of 6357 km and an equatorial radius of 6378 km.</p>
<p>R&#8217; = a * (1 &#8211; e<sup class="moz-txt-sup">2</sup>) / (1 &#8211; e<sup class="moz-txt-sup">2</sup> * sin<sup class="moz-txt-sup">2</sup>(lat))^(3/2)</p>
<p>where a is the equatorial radius, b is the polar radius, and<br />
e is the eccentricity of the ellipsoid = (1 &#8211; b<sup class="moz-txt-sup">2</sup>/a<sup class="moz-txt-sup">2</sup>)^(1/2).</p>
<p>Wow! So there you have it.</p>
<p>Of course if you&#8217;re trying to compute these values in client side javascript, it may take a while. It turns out that for short-ish distances at latitutudes within the continental United States, just pretending the Earth is a sphere yields errors of roughly 20 meters. That&#8217;s good enough for me..</p>
<p>(All from Google and <a class="moz-txt-link-freetext" href="http://www.faqs.org/faqs/geography/infosystems-faq/">http://www.faqs.org/faqs/geography/infosystems-faq/</a> )</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2007/01/14/computing-distances-with-latlon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>KML in Google Maps and the challenge of standards</title>
		<link>http://blog.oroup.com/2006/12/27/kml-in-google-maps-and-the-challenge-of-standards/</link>
		<comments>http://blog.oroup.com/2006/12/27/kml-in-google-maps-and-the-challenge-of-standards/#comments</comments>
		<pubDate>Wed, 27 Dec 2006 16:53:05 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/2006/12/27/kml-in-google-maps-and-the-challenge-of-standards/</guid>
		<description><![CDATA[<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0"><Response><name>91 N. MAIN ST., WARSAW NY 14569</name><Status><code>200</code><request>geocode</request></Status><Placemark><address>91 N Main St, Warsaw, NY 14569, USA</address><AddressDetails Accuracy="8" xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"><Country><CountryNameCode>US</CountryNameCode><AdministrativeArea><AdministrativeAreaName>NY</AdministrativeAreaName><SubAdministrativeArea><SubAdministrativeAreaName>Wyoming</SubAdministrativeAreaName><Locality><LocalityName>Warsaw</LocalityName><Thoroughfare><ThoroughfareName>91 N Main St</ThoroughfareName></Thoroughfare><PostalCode><PostalCodeNumber>14569</PostalCodeNumber></PostalCode></Locality></SubAdministrativeArea></AdministrativeArea></Country></AddressDetails><Point><coordinates>-78.132576,42.741659,0</coordinates></Point></Placemark></Response></kml>]]></description>
			<content:encoded><![CDATA[<p>The Google Maps API is generally a pleasure to work with. After more or less inventing the whole Web 2.0 thing, the people behind Google Maps have continued to innovate, recently adding a Geocoder to their API, allowing address information to be translated into coordinates in Latitude and Longitude. Naturally having this information expands considerably the number of things you can do with Google Maps. Even better, it doesn&#8217;t just return Coordinates for an address, it &#8220;normalizes&#8221; a query and returns the address in a structured way.<br />
There&#8217;s no doubt that creating a global XML standard for addresses must have been a challenging thing to try and do. Some countries use street names in addresses others do not. Some nations use island names, others have no islands. Some (like America) has county names but do not use them in addresses. So Kudos to OASIS for creating a standard called <a href="http://www.oasis-open.org/committees/ciq/ciq.html#6">xAL</a> and kudos to Google for trying to use it in their Google Maps API. Unfortunately, the devil is always in the details.</p>
<p><span id="more-10"></span></p>
<p>First, OASIS makes reading the standard harder than it should be by making you download a <a href="http://www.oasis-open.org/committees/ciq/Downloads/ciq_all.zip">10 megabyte zip</a> file containing a whole bunch of standards, not all of which are currently relevant to me. Law #1 in the web age: Google is the source of all* traffic. The only reason I even found them is because Google helpfully links them.</p>
<p>While it&#8217;s clearly better than nothing, the following quote from the spec tells much of the story: <em>xAL can be used to define addresses in simple terms or in complex terms. It is up to the user to decide how they want to implement xAL.</em></p>
<p>I&#8217;d be very surprised if anyone anywhere has implemented software that can <em>read</em> and do something useful with the full range of XML that technically conforms to the spec. There&#8217;s just too much of it.<br />
Unfortunately (and as with all things this complex) there appear to be outright bugs in the Google implementation. Take two address examples:</p>
<p>Example #1: <a href="http://oroup.com/pub/google-maps-examples/gm-example-1.xml"> 91 N. MAIN ST., WARSAW NY 14569 </a> This address works beautifully and returns results as you might expect. There&#8217;s a hierarchy and each element in the hierarchy maps to a US centric address element:</p>
<ul>
<li>Country (Country)</li>
<ul>
<li>Administrative Area (State)</li>
</ul>
<ul>
<ul>
<li>Sub Administrative Area (County)</li>
</ul>
</ul>
<ul>
<ul>
<ul>
<li>Locality (City)</li>
</ul>
</ul>
</ul>
<ul>
<ul>
<ul>
<ul>
<li>ThoroughFare (Street)</li>
<li>PostalCode (Zip)</li>
</ul>
</ul>
</ul>
</ul>
</ul>
<p>Beautiful. Google has mapped US addresses nicely into the standard and it&#8217;s easy to write code that does useful things. Unfortunately, in my small sample, Google only returns results of this form about 87% of the time.</p>
<p>Example #2: <a href="http://oroup.com/pub/google-maps-examples/gm-example-2.xml">760 HOOSICK RD., TROY NY 12180</a> This address also works well but returns a different hierarchy:</p>
<ul>
<li>Country (Country)</li>
<ul>
<li>Administrative Area (State)</li>
<ul>
<li>Sub Administrative Area (City)</li>
</ul>
<ul>
<ul>
<li>ThoroughFare (Street)</li>
<li>PostalCode (Zip)</li>
</ul>
</ul>
</ul>
</ul>
<p>Notice that County information is missing. This is not a fatal problem and is to be expected with a dataset as large and noisy as addresses. However, rather than simply leaving Sub Administrative Area unnamed (as the spec seems to suggest with its examples) the API remaps the City up to the Sub Administrative Area and omits the Locality element. Notice also that ThoroughFare and PostalCode are no longer a child of Locality but of Sub-Administrative Area.</p>
<p>I&#8217;ve sent a link to this post to the folks at Google Maps. I&#8217;ll be interested to see whether they agree that it&#8217;s a bug or think they&#8217;re adhereing to the letter of the spec. That&#8217;s the challenge with standards. They either say to much or to little.</p>
<p>Note: The examples above link to cached versions of what Google returns when you connect with a valid Maps Key. I cannot easily figure out what a key for your host might be so you&#8217;ll need to get your own key and make your own queries to see the results for yourself.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2006/12/27/kml-in-google-maps-and-the-challenge-of-standards/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The joys of screenscraping</title>
		<link>http://blog.oroup.com/2006/11/05/the-joys-of-screenscraping/</link>
		<comments>http://blog.oroup.com/2006/11/05/the-joys-of-screenscraping/#comments</comments>
		<pubDate>Sun, 05 Nov 2006 15:58:10 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/2006/11/05/the-joys-of-screenscraping/</guid>
		<description><![CDATA[A while back, I ran across a great HackDiary entry extolling the virtues of using TagSoup and XPATH to do screenscraping from the web. TagSoup is a library that coerces all the ugly nasty HTML you find out in the wild into well-formed (although not necessarily valid) XML. While there&#8217;s no guarantee that the results [...]]]></description>
			<content:encoded><![CDATA[<p>A while back, I ran across a great <a href="http://www.hackdiary.com/archives/000041.html">HackDiary entry</a> extolling the virtues of using <a href="http://home.ccil.org/~cowan/XML/tagsoup/">TagSoup</a> and XPATH to do screenscraping from the web. TagSoup is a library that coerces all the ugly nasty HTML you find out in the wild into well-formed (although not necessarily valid) XML. While there&#8217;s no guarantee that the results are semantically the same as the input, it lets you use all your nice XML tools like XPATH to extract data. The entry does a great job of showing you how to use TagSoup with <a href="http://xml.apache.org/xalan-j/">Xalan</a>. However, the JDK has been updated with it&#8217;s own XPATH parser so it&#8217;s no longer necessary to import the Xalan library. Below is a code sample for using TagSoup and the default XPATH parser to retrieve the stock price of Google from Google Finance. Note that the whole &#8220;MutableNamespaceContext&#8221; implementation is just a workaround for a missing JDK method as documented in <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5101859">JDK Bug 5101859</a>. If that bug gets fixed, the code could be simplified substantially.</p>
<p>The usual disclaimers apply about this all being sample quality code. All error handling has been punted to keep the example length short, but you&#8217;d never really want to do that. Also, I&#8217;m having trouble preserving indenting in this HTML View, I&#8217;ll work on that. This code assumes JDK 1.5. Click through for the code itself.</p>
<p>Does this code support the <a href="http://www.oreilly.com/catalog/beyondjava/">argument</a> that Java is WAY too verbose? Absolutely.<br />
<span id="more-5"></span><br />
<style type="text/css">     <!--code { font-family: Courier New, Courier; font-size: 10pt; margin: 0px; }-->   </style>
<div align="left" class="java">
<table cellspacing="0" cellpadding="3" border="0" bgcolor="#ffffff">
<tr>
<td valign="top" nowrap="nowrap" align="left"><code> <font color="#3f5fbf">/**</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* Demo of screenscraping using TagSoup and XPATH as described at </font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* http://blog.oroup.com/2006/11/05/the-joys-of-screenscraping/</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* </font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* This example class downloads the content of a page from Google</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* Finance and parses it for the Google stock price. It completely</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* omits all error handling for brevity. Also a lot of objects</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* should be cached and re-used if you were really going to call</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* this multiple times.</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* </font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@author </font><font color="#3f5fbf">Oliver Roup <<a href="mailto:oroup@oroup.com">oroup@oroup.com</a>></font><font color="#7f7f9f"><br />
<font color="#ffffff"> </font><font color="#3f5fbf">*/</font><br />
<font color="#ffffff"><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.io.InputStream;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.io.StringWriter;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.net.URL;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.net.URLConnection;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.util.ArrayList;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.util.HashMap;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.util.Iterator;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.util.List;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">java.util.Map;</font><br />
<font color="#ffffff"><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.namespace.NamespaceContext;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.OutputKeys;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.Result;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.Source;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.Transformer;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.TransformerFactory;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.dom.DOMResult;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.dom.DOMSource;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.sax.SAXTransformerFactory;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.sax.TransformerHandler;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.transform.stream.StreamResult;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.xpath.XPath;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.xpath.XPathConstants;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">javax.xml.xpath.XPathFactory;</font><br />
<font color="#ffffff"><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">org.w3c.dom.Node;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">org.w3c.dom.NodeList;</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">org.xml.sax.InputSource;</font><br />
<font color="#ffffff"><br />
<font color="#3f7f5f">// The Tagsoup library.</font><br />
<font color="#7f0055"><strong>import </strong></font><font color="#000000">org.ccil.cowan.tagsoup.Parser;</font><br />
<font color="#ffffff"><br />
<font color="#7f0055"><strong>public class </strong></font><font color="#000000">QueryHtml </font><font color="#000000">{</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public static </strong></font><font color="#7f0055"><strong>void </strong></font><font color="#000000">main</font><font color="#000000">(</font><font color="#000000">String</font><font color="#000000">[] </font><font color="#000000">args</font><font color="#000000">) </font><font color="#7f0055"><strong>throws </strong></font><font color="#000000">Exception </font><font color="#000000">{</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// Get the page and coerce it to an XML DOM. This loads the whole</font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// thing into memory so massive pages should be cut down first</font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// using SAX or something similar.</font><br />
<font color="#ffffff">    </font><font color="#000000">Node node = getHtmlUrlNode</font><font color="#000000">(</font><font color="#2a00ff">"http://finance.google.com/finance?q=GOOG"</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// Create a mutable namespace context. This should really be provided</font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// by the JDK, but the default implementation does not allow new entries</font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// to be added.</font><br />
<font color="#ffffff">    </font><font color="#000000">MutableNamespaceContext nc = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">MutableNamespaceContext</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// Set the prefix "html" to correspond to the xhtml namespace.</font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// This can be called multiple times with different prefixes.</font><br />
<font color="#ffffff">    </font><font color="#000000">nc.setNamespace</font><font color="#000000">(</font><font color="#2a00ff">"html"</font><font color="#000000">, </font><font color="#2a00ff">"http://www.w3.org/1999/xhtml"</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// This is the query we run against the DOM coereced from the web page.</font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// If the HTML changes in a relevant way, it will break this query. </font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>final </strong></font><font color="#000000">String QUERY = </font><font color="#2a00ff">"/html:html/html:body/html:table[2]/html:tr" </font><font color="#000000">+ </font><br />
<font color="#ffffff">      </font><font color="#2a00ff">"/html:td/html:table/html:tr[2]/html:td[2]/html:div/html:table" </font><font color="#000000">+ </font><br />
<font color="#ffffff">      </font><font color="#2a00ff">"/html:tr/html:td/html:span/html:span/text()"</font><font color="#000000">;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// Run the xpath query against the DOM.</font><br />
<font color="#ffffff">    </font><font color="#000000">NodeList result = xPathQuery</font><font color="#000000">(</font><font color="#000000">node, QUERY, nc</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// Print out the result.</font><br />
<font color="#ffffff">    </font><font color="#000000">System.out.println</font><font color="#000000">(</font><font color="#000000">dumpNode</font><font color="#000000">(</font><font color="#000000">result.item</font><font color="#000000">(</font><font color="#990000">0</font><font color="#000000">)</font><font color="#000000">, </font><font color="#7f0055"><strong>true</strong></font><font color="#000000">))</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#3f5fbf">/**</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@param </font><font color="#3f5fbf">urlString The URL of the page to retrieve</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@return </font><font color="#3f5fbf">A Node with a well formed XML doc coerced from the page.</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@throws </font><font color="#3f5fbf">Exception if something goes wrong. No error handling at all</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* for brevity.</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">*/</font><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public static </strong></font><font color="#000000">Node getHtmlUrlNode</font><font color="#000000">(</font><font color="#000000">String urlString</font><font color="#000000">) </font><font color="#7f0055"><strong>throws </strong></font><font color="#000000">Exception </font><font color="#000000">{</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#000000">SAXTransformerFactory stf = </font><br />
<font color="#ffffff">      </font><font color="#000000">(</font><font color="#000000">SAXTransformerFactory</font><font color="#000000">) </font><font color="#000000">TransformerFactory.newInstance</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">TransformerHandler th = stf.newTransformerHandler</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// This dom result will contain the results of the transformation</font><br />
<font color="#ffffff">    </font><font color="#000000">DOMResult dr = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">DOMResult</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">th.setResult</font><font color="#000000">(</font><font color="#000000">dr</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#000000">Parser parser = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">Parser</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">parser.setContentHandler</font><font color="#000000">(</font><font color="#000000">th</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">    </font><font color="#000000">URL url = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">URL</font><font color="#000000">(</font><font color="#000000">urlString</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">      </font><font color="#000000">URLConnection urlConn = url.openConnection</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">      </font><font color="#000000">InputStream stream = urlConn.getInputStream</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><br />
<font color="#ffffff">    </font><font color="#3f7f5f">// This is where the magic happens to convert HTML to XML</font><br />
<font color="#ffffff">    </font><font color="#000000">parser.parse</font><font color="#000000">(</font><font color="#7f0055"><strong>new </strong></font><font color="#000000">InputSource</font><font color="#000000">(</font><font color="#000000">stream</font><font color="#000000">))</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>return </strong></font><font color="#000000">dr.getNode</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff">  </font><br />
<font color="#ffffff">  </font><font color="#3f5fbf">/**</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@param </font><font color="#3f5fbf">node An XML DOM Tree for query</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@param </font><font color="#3f5fbf">query An XPATH query to run against the DOM Tree</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@param </font><font color="#3f5fbf">nc The namespaceContext that maps prefixes to XML namespace</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@return </font><font color="#3f5fbf">A list of nodes that result from running the query against</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* the node.</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@throws </font><font color="#3f5fbf">Exception If anything goes wrong. No error handling for brevity</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">*/</font><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public static </strong></font><font color="#000000">NodeList xPathQuery</font><font color="#000000">(</font><font color="#000000">Node node, String query, </font><br />
<font color="#ffffff">      </font><font color="#000000">NamespaceContext nc</font><font color="#000000">) </font><font color="#7f0055"><strong>throws </strong></font><font color="#000000">Exception </font><font color="#000000">{</font><br />
<font color="#ffffff">    </font><font color="#000000">XPathFactory xpf = XPathFactory.newInstance</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">XPath xpath = xpf.newXPath</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">xpath.setNamespaceContext</font><font color="#000000">(</font><font color="#000000">nc</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>return </strong></font><font color="#000000">(</font><font color="#000000">NodeList</font><font color="#000000">) </font><font color="#000000">xpath.evaluate</font><font color="#000000">(</font><font color="#000000">query, node, XPathConstants.NODESET</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#3f5fbf">/**</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@param </font><font color="#3f5fbf">node A node to be dumped to a string</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@param </font><font color="#3f5fbf">omitDeclaration A boolean whether to omit the XML declaration</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@return </font><font color="#3f5fbf">A string representation of the node.</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@throws </font><font color="#3f5fbf">Exception If anything goes wrong. Error handling omitted.</font><br />
<font color="#ffffff">   </font><font color="#3f5fbf">*/</font><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public static </strong></font><font color="#000000">String dumpNode</font><font color="#000000">(</font><font color="#000000">Node node, </font><font color="#7f0055"><strong>boolean </strong></font><font color="#000000">omitDeclaration</font><font color="#000000">) </font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>throws </strong></font><font color="#000000">Exception </font><font color="#000000">{</font><br />
<font color="#ffffff">    </font><font color="#000000">Transformer xformer = </font><br />
<font color="#ffffff">      </font><font color="#000000">TransformerFactory.newInstance</font><font color="#000000">()</font><font color="#000000">.newTransformer</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>if </strong></font><font color="#000000">(</font><font color="#000000">omitDeclaration</font><font color="#000000">) {</font><br />
<font color="#ffffff">      </font><font color="#000000">xformer.setOutputProperty</font><font color="#000000">(</font><font color="#000000">OutputKeys.OMIT_XML_DECLARATION, </font><font color="#2a00ff">"yes"</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">}</font><br />
<font color="#ffffff">    </font><font color="#000000">StringWriter sw = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">StringWriter</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">Result result = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">StreamResult</font><font color="#000000">(</font><font color="#000000">sw</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">Source source = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">DOMSource</font><font color="#000000">(</font><font color="#000000">node</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#000000">xformer.transform</font><font color="#000000">(</font><font color="#000000">source, result</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>return </strong></font><font color="#000000">sw.toString</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff">  </font><br />
<font color="#000000">}</font><br />
<font color="#ffffff"><br />
<font color="#3f5fbf">/** There is a bug in the JDK which omits the setNamespace declaration</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* from implementations of NamespaceContext. We have to create our</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* own implementation to work around it. Documented here:</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5101859</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">* </font><font color="#7f9fbf">@author </font><font color="#3f5fbf">Oliver Roup &lt;oroup@oroup.com&gt;</font><br />
<font color="#ffffff"> </font><font color="#3f5fbf">*/</font><br />
<font color="#7f0055"><strong>class </strong></font><font color="#000000">MutableNamespaceContext </font><font color="#7f0055"><strong>implements </strong></font><font color="#000000">NamespaceContext </font><font color="#000000">{</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>private </strong></font><font color="#000000">Map map;</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public </strong></font><font color="#000000">MutableNamespaceContext</font><font color="#000000">() {</font><br />
<font color="#ffffff">    </font><font color="#000000">map = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">HashMap</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public </strong></font><font color="#7f0055"><strong>void </strong></font><font color="#000000">setNamespace</font><font color="#000000">(</font><font color="#000000">String prefix, String namespaceURI</font><font color="#000000">) {</font><br />
<font color="#ffffff">    </font><font color="#000000">map.put</font><font color="#000000">(</font><font color="#000000">prefix, namespaceURI</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public </strong></font><font color="#000000">String getNamespaceURI</font><font color="#000000">(</font><font color="#000000">String prefix</font><font color="#000000">) {</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>return </strong></font><font color="#000000">map.get</font><font color="#000000">(</font><font color="#000000">prefix</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public </strong></font><font color="#000000">String getPrefix</font><font color="#000000">(</font><font color="#000000">String namespaceURI</font><font color="#000000">) {</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>for </strong></font><font color="#000000">(</font><font color="#000000">String prefix : map.keySet</font><font color="#000000">()) {</font><br />
<font color="#ffffff">      </font><font color="#7f0055"><strong>if </strong></font><font color="#000000">(</font><font color="#000000">map.get</font><font color="#000000">(</font><font color="#000000">prefix</font><font color="#000000">)</font><font color="#000000">.equals</font><font color="#000000">(</font><font color="#000000">namespaceURI</font><font color="#000000">)) {</font><br />
<font color="#ffffff">        </font><font color="#7f0055"><strong>return </strong></font><font color="#000000">prefix;</font><br />
<font color="#ffffff">      </font><font color="#000000">}</font><br />
<font color="#ffffff">    </font><font color="#000000">}</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>return null</strong></font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#ffffff"><br />
<font color="#ffffff">  </font><font color="#7f0055"><strong>public </strong></font><font color="#000000">Iterator getPrefixes</font><font color="#000000">(</font><font color="#000000">String namespaceURI</font><font color="#000000">) {</font><br />
<font color="#ffffff">    </font><font color="#000000">List prefixes = </font><font color="#7f0055"><strong>new </strong></font><font color="#000000">ArrayList</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>for </strong></font><font color="#000000">(</font><font color="#000000">String prefix : map.keySet</font><font color="#000000">()) {</font><br />
<font color="#ffffff">      </font><font color="#7f0055"><strong>if </strong></font><font color="#000000">(</font><font color="#000000">map.get</font><font color="#000000">(</font><font color="#000000">prefix</font><font color="#000000">)</font><font color="#000000">.equals</font><font color="#000000">(</font><font color="#000000">namespaceURI</font><font color="#000000">)) {</font><br />
<font color="#ffffff">        </font><font color="#000000">prefixes.add</font><font color="#000000">(</font><font color="#000000">prefix</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">      </font><font color="#000000">}</font><br />
<font color="#ffffff">    </font><font color="#000000">}</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>return </strong></font><font color="#000000">prefixes.iterator</font><font color="#000000">()</font><font color="#000000">;</font><br />
<font color="#ffffff">  </font><font color="#000000">}</font><br />
<font color="#000000">}  </font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></code><font color="#7f7f9f"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff"><font color="#ffffff">         </font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></td>
</tr>
</table>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2006/11/05/the-joys-of-screenscraping/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Postfix</title>
		<link>http://blog.oroup.com/2006/11/04/postfix/</link>
		<comments>http://blog.oroup.com/2006/11/04/postfix/#comments</comments>
		<pubDate>Sat, 04 Nov 2006 17:07:53 +0000</pubDate>
		<dc:creator>oroup</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://blog.oroup.com/2006/11/04/postfix/</guid>
		<description><![CDATA[My rimu host hosts a number of domains, including oroup.com, openrelay.com, cadabraco.com and drugmaps.com. I want to be able to send and receive email to those domains, but (at least for now) I don&#8217;t really want to set up dovecot locally and actually deal with mail. So the ideal thing is just to forward your [...]]]></description>
			<content:encoded><![CDATA[<p>My rimu host hosts a number of domains, including <a href="http://oroup.com">oroup.com</a>, <a href="http://openrelay.com">openrelay.com</a>, <a href="http://cadabraco.com">cadabraco.com</a> and <a href="http://www.drugmaps.com">drugmaps.com</a>. I want to be able to send and receive email to those domains, but (at least for now) I don&#8217;t really want to set up dovecot locally and actually deal with mail. So the ideal thing is just to forward your mail to another email address. Postfix is a little daunting at first, but the key <a href="http://www.postfix.org/VIRTUAL_README.html#forwarding">instructions</a> turn out to be quite simple.</p>
<blockquote>
<pre>1 /etc/postfix/main.cf:
2     <a href="http://www.postfix.org/postconf.5.html#virtual_alias_domains">virtual_alias_domains</a> = example.com ...other <a href="http://www.postfix.org/VIRTUAL_README.html#canonical">hosted domains</a>...
3     <a href="http://www.postfix.org/postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> = hash:/etc/postfix/virtual
4
5 /etc/postfix/virtual:
6     postmaster@example.com postmaster
7     joe@example.com        joe@somewhere
8     jane@example.com       jane@somewhere-else
9     # Uncomment entry below to implement a catch-all address
10     # @example.com         jim@yet-another-site
11     ...virtual aliases for more domains...</pre>
</blockquote>
<p>Presto, instant email!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.oroup.com/2006/11/04/postfix/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
