<?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>David Janes&#039; Code Weblog &#187; demo</title>
	<atom:link href="http://code.davidjanes.com/blog/category/demo/feed/" rel="self" type="application/rss+xml" />
	<link>http://code.davidjanes.com/blog</link>
	<description></description>
	<lastBuildDate>Fri, 03 Feb 2012 00:49:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Using Pipe Cleaner to convert CSV list of Science Journals to an OPML subscription list</title>
		<link>http://code.davidjanes.com/blog/2009/02/21/using-pipe-cleaner-to-convert-csv-list-of-science-journals-to-an-opml-subscription-list/</link>
		<comments>http://code.davidjanes.com/blog/2009/02/21/using-pipe-cleaner-to-convert-csv-list-of-science-journals-to-an-opml-subscription-list/#comments</comments>
		<pubDate>Sat, 21 Feb 2009 20:43:02 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[pipe cleaner]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=483</guid>
		<description><![CDATA[Here&#8217;s a Pipe Cleaner script to convert this text list of Science Journals and converts it an OPML subscription list (here) import module:api_csv.CSV; CSV uri:'http://www.tictocs.ac.uk/text.php' delimeter:'\t'; items := map value:$items map:{ "title" : "{{ C1 }}", "links" : { "href" : "{{ C2 }}", "type" : "text/xml", "rel" : "alternate", } }; I decided not [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a Pipe Cleaner script to convert <a href="http://www.tictocs.ac.uk/text.php">this text list of Science Journals</a> and converts it an OPML subscription list (<a href="http://code.davidjanes.com/examples/2009-02-21/science-journals.opml">here</a>)</p>
<pre>import module:api_csv.CSV;

CSV uri:'http://www.tictocs.ac.uk/text.php' delimeter:'\t';

items := map value:$items map:{
    "title" : "{{ C1 }}",
    "links" : {
        "href" : "{{ C2 }}",
        "type" : "text/xml",
        "rel" : "alternate",
    }
};</pre>
<p>I decided not to use the &#8220;header name&#8221; feature of the CSV command because I had to remap anyway to create the <code>links</code> object. This has to be run with the following command (or from the web UI):</p>
<pre>pc --format opml science-journals</pre>
<p>Of course, this is a little unwieldy in size so maybe you only want journals with &#8220;Astrophysics&#8221; in their title:</p>
<pre>import module:api_csv.CSV;

CSV uri:'http://www.tictocs.ac.uk/text.php' delimeter:'\t';

items := map value:$items map:{
    "title" : "{{ C1 }}",
    "links" : {
        "href" : "{{ C2 }}",
        "type" : "text/xml",
        "rel" : "alternate",
    }
};

items := search value:$items for:"Astrophysics";</pre>
<p>Cool, eh? Not only this, this can be run entirely from the Web Interface with selectable strings so (theoretically) a Pipe Cleaner user would have an API to this data.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2009/02/21/using-pipe-cleaner-to-convert-csv-list-of-science-journals-to-an-opml-subscription-list/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pipe Cleaner &#8211; a delicious example</title>
		<link>http://code.davidjanes.com/blog/2009/01/26/pipe-cleaner-a-delicious-example/</link>
		<comments>http://code.davidjanes.com/blog/2009/01/26/pipe-cleaner-a-delicious-example/#comments</comments>
		<pubDate>Tue, 27 Jan 2009 00:08:40 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[pipe cleaner]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=464</guid>
		<description><![CDATA[This is going to be a very brief post: here&#8217;s how you use Pipe Cleaner to download every in your delicious account tagged &#8220;python&#8221;  &#8211; outputing it as OPML, RSS, or Atom comes for free: import module:api_delicious; api_delicious.PostsList to:items tag:"python" authenticate:delicious;]]></description>
			<content:encoded><![CDATA[<p>This is going to be a very brief post: here&#8217;s how you use Pipe Cleaner to download every in your delicious account tagged &#8220;python&#8221;  &#8211; outputing it as OPML, RSS, or Atom comes for free:</p>
<pre>import module:api_delicious;
api_delicious.PostsList to:items tag:"python" authenticate:delicious;</pre>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2009/01/26/pipe-cleaner-a-delicious-example/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating OPML subscription lists using Pipe Cleaner</title>
		<link>http://code.davidjanes.com/blog/2009/01/25/creating-opml-subscription-lists-using-pipe-cleaner/</link>
		<comments>http://code.davidjanes.com/blog/2009/01/25/creating-opml-subscription-lists-using-pipe-cleaner/#comments</comments>
		<pubDate>Sun, 25 Jan 2009 16:40:30 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[authentication]]></category>
		<category><![CDATA[demo]]></category>
		<category><![CDATA[pipe cleaner]]></category>
		<category><![CDATA[pybm]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=433</guid>
		<description><![CDATA[Here&#8217;s a neat API I completed this morning, called api_feeds. It takes a URL (or a list of them) and transforms them into: the home page associated with the URL the feed(s) for the URL the name of the home page If you&#8217;re following along at home, this is essentially the information needed for a [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a neat API I completed this morning, called <code>api_feeds</code>. It takes a URL (or a list of them) and transforms them into:</p>
<ul>
<li>the home page associated with the URL</li>
<li>the feed(s) for the URL</li>
<li>the name of the home page</li>
</ul>
<p>If you&#8217;re following along at home, this is essentially the information needed for a single <code>outline</code> in an <a href="http://www.opml.org/spec2#subscriptionLists">OPML subscription list</a>.</p>
<p>Here&#8217;s a simple python example:</p>
<pre>api = api_feeds.OneFeed()
api.request = {
    "uri" : "http://code.davidjanes.com/blog/2009/01/23/transparently-working-with-oauath/",
}

pprint.pprint(api.response, width = 1)</pre>
<p>And here&#8217;s what the output looks like:</p>
<pre>{'link': u'http://code.davidjanes.com/blog',
 'links': [{'href': u'http://feeds.feedburner.com/DavidJanesCode',
            'rel': 'alternate',
            'type': u'application/rss+xml'}],
 'title': u"David Janes' Code Weblog"}</pre>
<p>There&#8217;s actually quite a bit going on here behind the scenes, most of it using code I didn&#8217;t initially write but have quite heavily hacked: the <a href="http://www.feedparser.org/">Universal Feed Parser</a> and the <a href="http://pypi.python.org/pypi/feedfinder/1.371">Feed Finder</a>.</p>
<p>What becomes really interesting what happens when we combine this with other modules. Here&#8217;s an example of how we can build an OPML subscription list from all the posts I&#8217;ve tagged &#8220;python&#8221; and &#8220;django&#8221; in <a href="http://delicious.com/dpjanes/python+django">del.icio.us</a>. The code looks up each link I&#8217;ve bookmarked, does the feed discovery above, filters out items that don&#8217;t have feeds, and outputs as OPML. Note the neat pipeline type aspect to the code:</p>
<pre>api_delicious = api_delicious.PostsList(tag = "python django")
api_many = api_feeds.ManyFeeds(require_feed = True)
api_opml = api_opml.OPMLWriter()

api_many.items = api_delicious.items
api_opml.items = api_many.items

print api_opml.Produce()</pre>
<p>Producing the following OPML:</p>
<pre>&lt;opml encoding="utf-8" version="2.0"&gt;
  &lt;head&gt;
    &lt;title&gt;[Untitled]&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;outline htmlUrl="http://push.cx"
      rssUrl="http://push.cx/feed"
      text="Push cx"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://crankycoder.com"
      rssUrl="http://crankycoder.com/feed/"
      text="crankycoder.com"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://blog.dowski.com"
      rssUrl="http://blog.dowski.com/feed/"
      text="the occasional occurrence"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://www.b-list.org/feeds/entries/"
      rssUrl="http://feeds2.feedburner.com/b-list-entries"
      text="The B-List: Latest entries"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://blog.thescoop.org"
      rssUrl="http://blog.thescoop.org/feed/"
      text="The Scoop"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://effbot.org"
      rssUrl="http://effbot.org/zone/rss.xml"
      text="effbot.org"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://blog.disqus.net"
      rssUrl="http://feeds.feedburner.com/BigHeadLabs"
      text="Disqus"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://blog.ianbicking.org"
      rssUrl="http://blog.ianbicking.org/feed/atom/"
      text="Ian Bicking: a blog"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://antoniocangiano.com"
      rssUrl="http://feeds.feedburner.com/ZenAndTheArtOfRubyProgramming"
      text="Zen and the Art of Programming"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://www.carthage.edu/webdev"
      rssUrl="http://www.carthage.edu/webdev/?feed=rss2"
      text="carthage webdev"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://www.eweek.com"
      rssUrl="http://www.eweek.com/rss-feeds-13.xml"
      text="Application Development - RSS Feeds"
      type="rss"/&gt;
    &lt;outline htmlUrl="http://jeffcroft.com/"
      rssUrl="http://feeds.feedburner.com/jeffcroft/blog"
      text="JeffCroft.com: Latest blog entries"
      type="rss"/&gt;
  &lt;/body&gt;
&lt;/opml&gt;</pre>
<p>This will be just as terse (terser, probably) when written as a Pipe Cleaner script; I&#8217;m just struggling over how to introduce the authentication code gracefully into the scripts.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2009/01/25/creating-opml-subscription-lists-using-pipe-cleaner/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Transparently working with OAuath</title>
		<link>http://code.davidjanes.com/blog/2009/01/23/transparently-working-with-oauath/</link>
		<comments>http://code.davidjanes.com/blog/2009/01/23/transparently-working-with-oauath/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 10:03:45 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[authentication]]></category>
		<category><![CDATA[demo]]></category>
		<category><![CDATA[pipe cleaner]]></category>
		<category><![CDATA[pybm]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=414</guid>
		<description><![CDATA[This is part one of two posts I&#8217;m going to write about OAuth; the second will be somewhat more critical in tone. Before I criticize &#8211; and I know it&#8217;s hard to put together technologically things like OAuth &#8211; I want to actually accomplish something with it, so I at least I appear that I [...]]]></description>
			<content:encoded><![CDATA[<p>This is part one of two posts I&#8217;m going to write about <a href="http://oauth.net/">OAuth</a>; the second will be somewhat more critical in tone. Before I criticize &#8211; and I know it&#8217;s hard to put together technologically things like OAuth &#8211; I want to actually accomplish something with it, so I at least I appear that I have somewhat of a clue about it. This is a report of what I&#8217;ve done.</p>
<p><code>bm_uri</code> is a libary and tool I&#8217;ve written for working with URIs, and in particular <code>http://</code> and <code>https://</code> URLs. Here are some of the advantages of using <code>bm_uri</code> over all the normal Python <code>urllib</code> and <code>urllib2</code> methods:</p>
<ul>
<li>downloads are cached; if a URL is temporarily not available, <code>bm_uri</code> will return the cached version, likewise if it has been downloaded in the near past, the cached version will be returned rather than hitting the net again</li>
<li>downloads can be <em>cooked</em>, meaning converted into a more useful form such as TIDY-cleaned up HTML, JSON, Unicode text and so forth</li>
<li><code>bm_uri</code> handles all the protocol stuff for you (such as User-Agent, Last-Modified and so forth) so you don&#8217;t have to</li>
<li>authentication is handled &#8220;invisibly&#8221; as possible for you &#8230; at least after the initial setup</li>
</ul>
<p>Here is an example of accessing a OAuth resource using <code>bm_uri</code> returning my current location from <a href="http://fireeagle.yahoo.net/">Fire Eagle</a> as a Python object. From a programming point of a view, I believe I have reduced this to close to the minimum number of steps possible. Here&#8217;s the setup phase:</p>
<pre>import bm_uri
import bm_oauth
import pprint

bm_cfg.cfg.initialize()

bm_oauth.OAuth(service_name = "fireeagle")</pre>
<p>Here&#8217;s using it in code &#8211; note how there&#8217;s no reference to OAuth here whatsoever.</p>
<pre>loader = bm_uri.JSONLoader('https://fireeagle.yahooapis.com/api/0.1/user.json?format=json')
loader.Load()

pprint.pprint(loader.GetCooked())</pre>
<p>And here&#8217;s the output of the program:</p>
<pre>{u'stat': u'ok',
 u'user': {u'location_hierarchy': [{u'best_guess': True,
         u'geometry': {u'coordinates': [-79.418426513699998,
                   43.731891632100002],
              u'type': u'Point'},
         u'id': 572261,
         u'label': None,
         u'level': 1,
         u'level_name': u'postal',
         u'located_at': u'2008-03-19T04:09:30-07:00',
...
         u'name': u'Canada',
         u'normal_name': None,
         u'place_id': u'EESRy8qbApgaeIkbsA',
         u'woeid': 23424775}],
     u'readable': True,
     u'writable': False}}</pre>
<h4>Gather information</h4>
<p>The devil is in the details, obviously and with OAuth, the little satan is doing the initial setup. Here&#8217;s how I did this for Fire Eagle &#8211; there&#8217;ll be something analogous for whatever service you are using:</p>
<ul>
<li>Log in or sign up (obviously)</li>
<li>Go to the <a href="http://fireeagle.yahoo.net/developer">Developers&#8217; Page</a></li>
<li>Click on <a href="https://fireeagle.yahoo.net/developer/create">Create a New App</a></li>
<li>Copy the &#8220;Consumer Key&#8221; and the &#8220;Consumer Secret&#8221; &#8230; these will be long-ish strings of nonsense</li>
<li>Find out the Request Token URL, the Access Token URL, and the Authorization URL. These are public knowledge and for Fire Eagle are:
<ul>
<li>https://fireeagle.yahooapis.com/oauth/request_token</li>
<li>https://fireeagle.yahooapis.com/oauth/access_token</li>
<li>http://fireeagle.yahoo.net/oauth/authorize</li>
</ul>
</li>
</ul>
<p><em>Note how Yahoo has conveniently made that last URL similar looking to the others, but not quite the same. Thanks!</em></p>
<p>However you implement OAuth, you&#8217;re probably going to need to be able to persist information to disk or database. As documented here several weeks ago, <a href="http://code.davidjanes.com/blog/2009/01/09/thinking-about-configuration/">we already have that covered</a> with our bm_cfg module. In <code>~/.cfg/fireeagle.json</code>, create the following JSON format file:</p>
<pre>{
 "fireeagle": {
  "api_uri" : "https://fireeagle.yahooapis.com/",
  "oauth_access_token_url": "https://fireeagle.yahooapis.com/oauth/access_token",
  "oauth_authorization_url": "http://fireeagle.yahoo.net/oauth/authorize",
  "oauth_consumer_key": "ABCDEFGHIJKL",
  "oauth_consumer_secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345",
  "oauth_token_url": "https://fireeagle.yahooapis.com/oauth/request_token",
 }
}</pre>
<p>The only new item here is the <code>api_uri</code>: that&#8217;s the prefix of URLs that <code>bm_uri</code> will use OAuth with.</p>
<h4>Set it up</h4>
<p>Next you have to do all sorts of OAuth stuff to actually work with OAuth. If the <em>why</em> interests you, <a href="http://oauth.net/core/1.0/">please go read the spec</a>! I&#8217;m more of <em>how</em> person myself, and this is what we need to do:</p>
<ul>
<li>run: <code>python bm_uri.py --service fireeagle --authorize</code></li>
<li>this will pop up a browser window; grant your application access and then&#8230;</li>
<li>run: <code>python bm_uri.py --service fireeagle --exchange</code></li>
</ul>
<p>And that&#8217;s it &#8211; you should now be able to just work with the Fire Eagle API in bm_uri without even having to know OAuth is there!</p>
<h4>End notes</h4>
<ul>
<li>the current implementation only works with HTTP/<a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a> GET; POST to come soon, DELETE and PUT as needed</li>
<li><code>bm_uri</code>, <code>bm_config</code> and the rest of the code is freely licensed and available <a href="http://code.google.com/p/pybm/">here</a>. It is a constantly changing product, albeit converging on perfection in my own mind <img src='http://code.davidjanes.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2009/01/23/transparently-working-with-oauath/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Atom as a Rosetta Stone for WORK objects</title>
		<link>http://code.davidjanes.com/blog/2009/01/19/atom-as-a-rosetta-stone-for-work-objects/</link>
		<comments>http://code.davidjanes.com/blog/2009/01/19/atom-as-a-rosetta-stone-for-work-objects/#comments</comments>
		<pubDate>Mon, 19 Jan 2009 11:31:04 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[pipe cleaner]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=408</guid>
		<description><![CDATA[WORK &#8211; Web Object Records &#8211; is a way of describing messages we pass over the web: a single header object called the &#8220;meta&#8221; and zero or more objects called &#8220;items&#8221;. Each object can be encoded as a JSON record, though we can access invidual items within each WORK object using a WORK Path which [...]]]></description>
			<content:encoded><![CDATA[<p><em><a href="http://code.davidjanes.com/blog/2008/11/11/work-web-object-records/">WORK</a> &#8211; Web Object Records &#8211; is a way of describing messages we pass over the web: a single header object called the &#8220;meta&#8221; and zero or more objects called &#8220;items&#8221;. Each object can be encoded as a JSON record, though we can access invidual items within each WORK object using a <a href="http://code.davidjanes.com/blog/2008/11/21/work-paths/">WORK Path</a> which allows quite a bit of latitude for type coercision and vagarities in packaging.</em></p>
<p><a href="http://code.davidjanes.com/blog/category/pipe-cleaner/">Pipe Cleaner</a> is a project I&#8217;ve been working on for the last two months that allows one to script data using WORK, to accomplish tasks such as remixing and filtering RSS feeds, read or produce <a href="http://www.opml.org/">OPML</a>, make JSON interfaces and so forth. I actually have one live deployment which I will blog about soon and hope to have it beta productized for March.</p>
<p><a href="http://atomenabled.org/">Atom</a> is a standard for syndicating feeds, not unsimilar to RSS but with a richer better described vocabulary. I already have one major &#8220;project&#8221; built around Atom: the <a href="http://microformats.org/wiki/hatom">hAtom microformat</a> for describing microcontent and information that can be syndicated. hAtom has also been morphed by Microsoft to produce the <a href="http://microformats.org/wiki/hatom">Web Slice format</a>, so you may be seeing that about. Atom is conforms to WORK: there&#8217;s a &#8220;feed&#8221; meta header and zero or more &#8220;entry&#8221; items.</p>
<p>With Pipe Cleaner I&#8217;m trying not only to make a way where feeds and other data can be remixed, <em>but also make it easy to do so</em>! To do that, I&#8217;ve decided that be default, even though you are working with (say) OPML or RSS, we&#8217;ll translate all the terms to their Atom equivalents as best as possible. You&#8217;ll have to read the spec yourselves, but here&#8217;s a quick rundown of common elements, not all required by any means:</p>
<ul>
<li><code>author</code>, with possible sub-fields <code>uri</code> and <code>email</code></li>
<li><code>content</code> &#8211; the body</li>
<li><code>summary</code> &#8211; a summary of the body; currently my feeling is that content &amp; summary must always be HTML</li>
<li><code>updated</code> &#8211; when last updated</li>
<li><code>created</code> &#8211; when created, assume to be updated if not present</li>
<li><code>link</code> &#8211; the main URI</li>
<li><code>links</code> &#8211; for alternate URIs (this is a variance from the Atom spec; it should be easy to find the main URI for an element; I may reconsider this before release)</li>
<li><code>id</code> &#8211; a unique identifier</li>
<li><code>category</code> &#8211; tags, encoded in a sub-field term</li>
</ul>
<p>Note that I&#8217;m not slavish about making the output conformant to all the SHOULDs, MUSTs, etc. that are in the Atom spec: my pragmatic programming approach says &#8220;do the best we can&#8221; and if the user needs better, they can walk the extra mile.</p>
<p>Here&#8217;s some examples of data that&#8217;s been run through Pipe Cleaner, translating to Atom upon input and translating back to whatever is needed upon output. The JSON (actually pretty printed JSON) output is the most instructive for what&#8217;s going to inside Pipe Cleaner.</p>
<h4>RSS Feed</h4>
<ul>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/rss.original.xml">source rss</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/rss.json.txt">rss -&gt; json</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/rss.opml.xml">rss -&gt; opml</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/rss.rss.xml">rss -&gt; rss</a></li>
</ul>
<h4>OPML Data</h4>
<p>Note how the OPML is &#8220;flattened&#8221;, with hierarchy being encoded into the Category. This can be turned off if needed.</p>
<ul>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/opml.original.xml">source opml</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/opml.json.txt">opml -&gt; json</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/opml.opml.xml">opml -&gt; opml</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/opml.rss.xml">opml -&gt; rss</a></li>
</ul>
<h4>hCard microformat (in HTML)</h4>
<p>Note the neat namespacing in the RSS output. The OPML is almost devoid of useful information, further consideration is needed.</p>
<ul>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcard.original.html">source hcard</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcard.json.txt">hcard -&gt; json</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcard.opml.xml">hcard -&gt; opml</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcard.rss.xml">hcard -&gt; rss</a></li>
</ul>
<h4>hCalendar microformat (in HTML)</h4>
<p>Similar to hCard. We&#8217;ll probably also (or exclusively) encode the hCalendar data in an <a href="http://en.wikipedia.org/wiki/XCal">xCal</a> extension.</p>
<ul>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcalendar.original.html">source hcalendar</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcalendar.json.txt">hcalendar -&gt; json</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcalendar.opml.xml">hcalendar -&gt; opml</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hcalendar.rss.xml">hcalendar -&gt; rss</a></li>
</ul>
<h4>hAtom microformat (in HTML)</h4>
<p>hAtom -&gt; RSS is basically turning an hAtom page into a feed!</p>
<ul>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hatom.original.html">source hatom</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hatom.json.txt">hatom -&gt; json</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hatom.opml.xml">hatom -&gt; opml</a></li>
<li><a href="http://code.davidjanes.com/examples/2009-01-19/xlate/hatom.rss.xml">hatom -&gt; rss</a></li>
</ul>
<h4>Source example</h4>
<p>Since no blog post is complete without a little source code, here&#8217;s a Pipe Cleaner script to parse the hCard document. If you&#8217;re following closely, the output format is selected by the user at runtime. All the other scripts are of similar terseness.</p>
<pre>import module:api_microformat;
api_microformat.HCard uri:"http://tantek.com/" to:items meta:meta;</pre>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2009/01/19/atom-as-a-rosetta-stone-for-work-objects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pipe Cleaner (II)</title>
		<link>http://code.davidjanes.com/blog/2008/12/23/pipe-cleaner-ii/</link>
		<comments>http://code.davidjanes.com/blog/2008/12/23/pipe-cleaner-ii/#comments</comments>
		<pubDate>Tue, 23 Dec 2008 11:37:58 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[pipe cleaner]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=388</guid>
		<description><![CDATA[Here&#8217;s the latest evolution of Pipe Cleaner, mainly recorded here for historical interest. The big change is that there isn&#8217;t a separate outside template &#8211; everything is in the one index.jd file. The new directive is template, which can read and execute an outside module or actually produce the final output (as we see in [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s the latest evolution of <a href="http://code.davidjanes.com/blog/2008/12/18/pipe-cleaner/">Pipe Cleaner</a>, mainly recorded here for historical interest. The big change is that there isn&#8217;t a separate outside template &#8211; everything is in the one <code>index.jd</code> file. The new directive is <code>template</code>, which can read and execute an outside module or actually produce the final output (as we see in the very last directive). I have not put this up as an independent demo.</p>
<pre>
#
#	Import the Python fire module
#	- used in: map from:"fire.GetGeocodedIncidents" to:"incidents"
#
import module:"fire";

#
#	Header for Google Maps popup
#	- used in: map from:"fire.GetGeocodedIncidents" to:"incidents"
#
#
set to:"fitem.head.map" value:"""
&lt;h3&gt;
&lt;a href="#{{ IncidentNumber }}"&gt;{{ AlarmLevel}}: {{ IncidentType }} on {{ RawStreet }}&lt;/a&gt;
&lt;/h3&gt;
""";

#
#	Header for the sidebar
#	- used in: map from:"fire.GetGeocodedIncidents" to:"incidents"
#
set to:"fitem.head.sb" value:"""
&lt;h3&gt;
{% if latitude and longitude %}
&lt;a href="javascript:js_maps.map.panTo(new GLatLng({{ latitude }}, {{ longitude }}))"&gt;*&lt;/a&gt;
{% endif %}
&lt;a href="#{{ IncidentNumber }}"&gt;{{ AlarmLevel}}: {{ IncidentType }} on {{ RawStreet }}&lt;/a&gt;
&lt;/h3&gt;
""";

#
#	Body for the Google Maps pop and the sidebar
#	- used in: map from:"fire.GetGeocodedIncidents" to:"incidents"
#
set to:"fitem.body" value:"""
&lt;p&gt;
Alarm Level: {{ AlarmLevel }}
&lt;br /&gt;
Incident Type: {{ IncidentType }}
&lt;br /&gt;
City: {{ City }}
&lt;br /&gt;
Street: {{ Street }} ({{ CrossStreet }})
&lt;br /&gt;
Units: {{ Units }}
&lt;/p&gt;
""";

#
#	Convert all the incidents from the fire module
#	to the path 'incidents' using the mapping rules defined above
#
#	- incidents are used in "gmaps.js" and "gmaps.html"
#
map from:"fire.GetGeocodedIncidents" to:"incidents" map:{
	"latitude" : "{{ latitude }}",
	"longitude" : "{{ longitude }}",
	"title" : "{{ AlarmLevel}}: {{ IncidentType }} on {{ RawStreet }}",
	"uri" : "{{ HOME_URI }}#{{ IncidentNumber }}",
	"body" : "{{ *fitem.head.map|safe }}{{ *fitem.body|safe }}",
	"body_sb" : "{{ *fitem.head.sb|safe }}{{ *fitem.body|safe }}",
	"IncidentNumber" : "{{ IncidentNumber }}"
};

#
#	Load the 'gmaps' templates (for arbitrary geo-mapping),
#	using the 'incidents' for its items and the specified meta.
#
#	- used in in "gmaps.js" and "gmaps.html"
#
set to:"map_meta" value_render:true value:{
	"id" : "maps",
	"latitude" : 43.67,
	"longitude" : -79.38,
	"uzoom" : -13,
	"gzoom" : 13,
	"api_key" : "{{ cfg.gmaps.api_key|otherwise:'ABQIAAA...pIxzZQ' }}",
	"html" : {
		"width" : "1024px",
		"height" : "800px"
	}
};

#
#	Produce GMaps
#
template script:"gmaps" items:"incidents" meta:"map_meta";

#
#	Produce the final output
#
template value:"""
&lt;html&gt;
&lt;head&gt;
    &lt;link rel="stylesheet" type="text/css" href="css.css" /&gt;
	{{ gmaps.js|safe }}
&lt;/head&gt;
&lt;body&gt;
&lt;div id="content_wrapper"&gt;
	&lt;div id="map_wrapper"&gt;
		{{ gmaps.html|safe }}
	&lt;/div&gt;
	&lt;div id="text_wrapper"&gt;
{% for incident in incidents %}
	&lt;div id="{{ incident.IncidentNumber }}"&gt;
		{{ incident.body_sb|safe }}
	&lt;/div&gt;
{% endfor %}
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
""";
</pre>
<p>The gmaps.jd (imported in the second last directive) looks like as follows (there will not be a test). It&#8217;s designed to be a universal &#8220;show a map and plot points on in it&#8221; inclusion. I&#8217;ve added a few line breaks so the <code>PRE</code> box doesn&#8217;t break.</p>
<pre>
#
#
#
template to:"html" value:"""
&lt;div id="id_{{ meta.id|jslug }}"
style="{% if meta.html.width %}width: {{ meta.html.width }};{% endif %}
{% if meta.html.height %} height: {{ meta.html.height }};{% endif %}
{% if meta.html.style %} style: {{ meta.html.style }};{% endif %}"
{% if meta.html.class %} class="{{ meta.html.class }}"{% endif %}
&gt;&lt;/div&gt;
&lt;script type="text/javascript"&gt;
js_{{ meta.id|jslug }}.onload();
&lt;/script&gt;
""";

#
#
#
template to:"js" value:"""
&lt;script
 type="text/javascript"
 src="http://maps.google.com/maps?file=api&amp;v=2&amp;key={{meta.api_key}}"&gt;
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
js_{{ meta.id|jslug }} = {
 onload : function() {
  js_{{ meta.id|jslug }}.map = new GMap2(document.getElementById("id_{{ meta.id|jslug }}"));
  m = js_{{ meta.id|jslug }}.map;
  m.setCenter(new GLatLng({{ meta.latitude }}, {{ meta.longitude }}), {{ meta.gzoom }});

  // {{ items|length }} items follow
{% for itemd in items %}
{% if itemd.latitude and itemd.longitude %}

  // {{ itemd.title }}
  var ll = new GLatLng({{ itemd.latitude }}, {{ itemd.longitude }});
  var marker = js_{{ meta.id|jslug }}.make_marker(m, ll, "{{ itemd.body|safe|escapejs }}");
  m.addOverlay(marker);
{% else %}
  // an item is missing latitude or longitude
{% endif %}
{% endfor %}
 },

 make_marker : function(m, ll, html) {
  var marker = new GMarker(ll);
  GEvent.addListener(marker, "click", function() {
   m.openInfoWindowHtml(ll, html);
  });

  return marker;
 },

 end : 0
}
&lt;/script&gt;
""";
</pre>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2008/12/23/pipe-cleaner-ii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Issues with utcoffset and pytz</title>
		<link>http://code.davidjanes.com/blog/2008/12/22/pytz-utcoffset/</link>
		<comments>http://code.davidjanes.com/blog/2008/12/22/pytz-utcoffset/#comments</comments>
		<pubDate>Mon, 22 Dec 2008 15:14:45 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=384</guid>
		<description><![CDATA[In the previous entry, we talked about the difficultly in finding out the delta from UTC for a timezone returned from the pytz module. In particular, consider the offset for St. John&#8217;s, Newfoundland which should be at -3:30. dt_now = datetime.datetime.now() tz = pytz.timezone('America/St_Johns') offset = tz.utcoffset(dt_now) Log( "using datetime.utcoffset", offset = format(offset), ) With [...]]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://code.davidjanes.com/blog/2008/12/22/working-with-dates-times-and-timezones-in-python/">previous entry,</a> we talked about the difficultly in finding out the delta from UTC for a timezone returned from the <a href="http://pytz.sourceforge.net/">pytz</a> module. In particular, consider the offset for <a href="http://en.wikipedia.org/wiki/St._John%27s,_Newfoundland_and_Labrador">St. John&#8217;s, Newfoundland</a> which should be at -3:30.</p>
<pre>dt_now = datetime.datetime.now()
tz = pytz.timezone('America/St_Johns')

offset = tz.utcoffset(dt_now)

Log(
    "using datetime.utcoffset",
    offset = format(offset),
)</pre>
<p>With the unexpected result:</p>
<pre class="result">  message: using datetime.utcoffset
  offset: -4:29 (-12660)</pre>
<p>I did a fair bit of Google searching for an answer without finding a satisfactory result, so I did further research on my own. To find the correct offset value, I found that this works:</p>
<pre>dt_sj = tz.localize(dt_now)
offset = dt_sj - pytz.UTC.localize(dt_now)

Log(
    "using delta to UTC",
    offset = format(offset),
)</pre>
<p>Which yields the correct:</p>
<pre class="result">  message: using delta to UTC
  offset: 03:30 (12600)</pre>
<p>Note that if you&#8217;re going to use the above method for finding deltas, you&#8217;re going to have to take Daylight Savings Time into consideration also. I have not done this here, as I&#8217;m a little pressed for time and just want to illustrate the problem.</p>
<p>The issue seems to be with the way that pytz uses the Olson database entry (from <a href="ftp://elsie.nci.nih.gov/pub/tzarchive.gz">here</a>) for St. John&#8217;s &#8211; and all other locations. It appears that pytz is using the first rule it sees, from 1884, rather than the rule for the date that was passed in. I think this is a bug.</p>
<pre>#
# St John's has an apostrophe, but Posix file names can't have apostrophes.
# Zone  NAME        GMTOFF  RULES   FORMAT  [UNTIL]
Zone America/St_Johns   -3:30:52 -  LMT 1884
            -3:30:52 StJohns N%sT   1918
            -3:30:52 Canada N%sT    1919
            -3:30:52 StJohns N%sT   1935 Mar 30
            -3:30   StJohns N%sT    1942 May 11
            -3:30   Canada  N%sT    1946
            -3:30   StJohns N%sT</pre>
<p>The setup code for the examples above is:</p>
<pre>from bm_log import Log
import dateutil.parser
import pytz
import datetime

def format(td):
    seconds = td.seconds + td.days * ( 24 * 3600 )
    return  "%02d:%02d (%s)" % ( seconds // 3600, seconds % 3600 // 60, seconds, )</pre>
<p><strong>Update 2010-03-09</strong>: <a href="https://bugs.launchpad.net/pytz/+bug/310606">This has been fixed in the code base</a> and (presumably) will be in the next upcoming release.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2008/12/22/pytz-utcoffset/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Working with dates, times and timezones in Python</title>
		<link>http://code.davidjanes.com/blog/2008/12/22/working-with-dates-times-and-timezones-in-python/</link>
		<comments>http://code.davidjanes.com/blog/2008/12/22/working-with-dates-times-and-timezones-in-python/#comments</comments>
		<pubDate>Mon, 22 Dec 2008 12:37:56 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=377</guid>
		<description><![CDATA[Here&#8217;s a few examples of working with dates, times and timezones in Python. We are using the following packages: datetime (part of the standard Python distribution) dateutil &#8211; for date parsing, though there&#8217;s a lot more depth to this package that I&#8217;m not touching here pytz &#8211; for timezone handling, and specifically making available the [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a few examples of working with dates, times and timezones in Python. We are using the following packages:</p>
<ul>
<li><a href="http://docs.python.org/library/datetime.html">datetime</a> (part of the standard Python distribution)</li>
<li><a href="http://labix.org/python-dateutil">dateutil</a> &#8211; for date parsing, though there&#8217;s a lot more depth to this package that I&#8217;m not touching here</li>
<li><a href="http://pytz.sourceforge.net/">pytz</a> &#8211; for timezone handling, and specifically making available the <a href="http://en.wikipedia.org/wiki/Zoneinfo">Olson timezone database</a> to Python</li>
</ul>
<p>There&#8217;s a lot of complexity to working with datetimes in any language; I&#8217;m not going to get into that but would prefer instead to show a few practical examples. Keep the following in mind:</p>
<ul>
<li>datetimes may or may not have timezones associated with them. If they do not, they are called &#8220;naive&#8221; and their meaning is effectively defined by the program. In general, you want to work with non-naive datetimes. Generally the assumption would be that the naive datetime is in the application&#8217;s current timezone or the user&#8217;s preferred timezone</li>
<li>when working with datetimes, consider the strategy of converting everything to the universal UTC timezone, then converting back to the user&#8217;s timezone only when you need to display that to the user</li>
<li>if you are rolling your own code for handling dates, times and timezones and you haven&#8217;t done a lot of research, your implementation is <strong>garbage</strong>. Do yourself and everyone else a favor and use a library.</li>
</ul>
<p>Our standard imports. <code>Log</code> is from the <a href="http://code.google.com/p/pybm/">pybm</a> library and it&#8217;s purpose is rather obvious.</p>
<pre>from bm_log import Log
import dateutil.parser
import pytz
import datetime</pre>
<p>Here&#8217;s an example of parsing the an e-mail or RSS type date using <code>dateutil</code>.</p>
<pre>dts = "Thu, 13 Nov 2008 05:41:35 +0000"
dt = dateutil.parser.parse(dts)

Log(
    "Parsing an RFC type date",
    src = dts,
    dt = dt,
    iso = dt.isoformat(),
)</pre>
<pre class="result">
  message: Parsing an RFC type date
  dt: 2008-11-13 05:41:35+00:00
  iso: 2008-11-13T05:41:35+00:00
  src: Thu, 13 Nov 2008 05:41:35 +0000
</pre>
<p>Here&#8217;s an example of parsing an ISO Datetime</p>
<pre>dts = '2008-11-13T05:41:35-0400'
dt = dateutil.parser.parse(dts)

Log(
    "Parsing an ISO Date with Timezone",
    src = dts,
    dt = dt,
    iso = dt.isoformat(),
)</pre>
<pre class="result">
  message: Parsing an ISO Date with Timezone
  dt: 2008-11-13 05:41:35-04:00
  iso: 2008-11-13T05:41:35-04:00
  src: 2008-11-13T05:41:35-0400
</pre>
<p>Here&#8217;s an example of parsing  a naive timezone.</p>
<pre>dts = '2008-11-13T05:41:35'
dt = dateutil.parser.parse(dts)

Log(
    "Parsing an ISO Date without a Timezone",
    src = dts,
    dt = dt,
    iso = dt.isoformat(),
)</pre>
<pre class="result">
  message: Parsing an ISO Date without a Timezone
  dt: 2008-11-13 05:41:35
  iso: 2008-11-13T05:41:35
  src: 2008-11-13T05:41:35
</pre>
<p>Here&#8217;s are two similar example, showing how to force the timezone if it&#8217;s not present. This will happen in the first part, but not the second.</p>
<pre>tz = pytz.timezone('America/Toronto')
dts = '2008-11-13T05:41:35'
dt = dateutil.parser.parse(dts)
if dt.tzinfo == None:
    dt = dt.replace(tzinfo = tz)

Log(
    "Parsing an ISO Date without a Timezone BUT specifying default TZ",
    src = dts,
    dt = dt,
    iso = dt.isoformat(),
    tz = tz,
)

tz = pytz.timezone('America/Toronto')
dts = '2008-11-13T05:41:35-0400'
dt = dateutil.parser.parse(dts)
if dt.tzinfo == None:
    dt = dt.replace(tzinfo = tz)

Log(
    "Parsing an ISO Date with a Timezone AND specifying default TZ",
    src = dts,
    dt = dt,
    iso = dt.isoformat(),
    tz = tz,
)</pre>
<pre class="result">
  message: Parsing an ISO Date without a Timezone BUT specifying default TZ
  dt: 2008-11-13 05:41:35-05:00
  iso: 2008-11-13T05:41:35-05:00
  src: 2008-11-13T05:41:35
  tz: America/Toronto

  message: Parsing an ISO Date with a Timezone AND specifying default TZ
  dt: 2008-11-13 05:41:35-04:00
  iso: 2008-11-13T05:41:35-04:00
  src: 2008-11-13T05:41:35-0400
  tz: America/Toronto
</pre>
<p>Update: here&#8217;s an example of moving datetimes to UTC and then to a different Timezone. Remember: you want your backend code to work with UTC datetimes for simplicity and correctness:</p>
<pre>
dts = '2008-11-13T05:41:35-0400'
dt_orig = dateutil.parser.parse(dts)
dt_utc = dt.astimezone(pytz.UTC)

Log(
    "Changing a datetime to UTC",
    src = dts,
    dt_orig = dt_orig,
    dt_utc = dt_utc,
)

tz_vancouver = pytz.timezone('America/Vancouver')
dt_vancouver = dt_utc.astimezone(tz_vancouver)

Log(
    "Changing UTC datetime to a different timezone",
    dt_vancouver = dt_vancouver,
    dt_utc = dt_utc,
)
</pre>
<pre class="result">
  message: Changing a datetime to UTC
  dt_orig: 2008-11-13 05:41:35-04:00
  dt_utc: 2008-11-13 09:41:35+00:00
  src: 2008-11-13T05:41:35-0400

  message: Changing UTC datetime to a different timezone
  dt_utc: 2008-11-13 09:41:35+00:00
  dt_vancouver: 2008-11-13 01:41:35-08:00
</pre>
<p>Here is an example of listing all &#8220;common&#8221; timezones using pytz. Note that &#8220;America&#8221; refers to the two continents, not the Irish word for the United States. Printing the actual timezone offset turned out to be a surprisingly complex task, which I will outline in a different blog post. For now let it suffice that with pytz try not to depend on <code>utcoffset</code>.</p>
<pre>dt_now = datetime.datetime.now()

def tzname2offset(tzname):
    dt_in_utc = pytz.UTC.localize(dt_now)
    dt_in_tz = pytz.timezone(tzname).localize(dt_now)

    offset = dt_in_utc - dt_in_tz
    seconds = offset.seconds + offset.days * ( 24 * 3600 )

    return  "%02d:%02d" % ( seconds // 3600, seconds % 3600 // 60, )

Log(
    "Olsen (pytz) common timezones and their UTC offsets",
    timezones = map(
        lambda tzname: ( tzname, tzname2offset(tzname), ),
        pytz.common_timezones,
    )
)</pre>
<pre class="result">
  message: Olsen (pytz) common timezones and their UTC offsets
  timezones:
    [('Africa/Abidjan', '00:00'),
     ('Africa/Accra', '00:00'),
     ('Africa/Addis_Ababa', '03:00'),
     ('Africa/Algiers', '01:00'),
     ('Africa/Asmara', '03:00'),
...
     ('Pacific/Wake', '12:00'),
     ('Pacific/Wallis', '12:00'),
     ('US/Alaska', '-9:00'),
     ('US/Arizona', '-7:00'),
     ('US/Central', '-6:00'),
     ('US/Eastern', '-5:00'),
     ('US/Hawaii', '-10:00'),
     ('US/Mountain', '-7:00'),
     ('US/Pacific', '-8:00'),
     ('UTC', '00:00')]
</pre>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2008/12/22/working-with-dates-times-and-timezones-in-python/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Pipe Cleaner</title>
		<link>http://code.davidjanes.com/blog/2008/12/18/pipe-cleaner/</link>
		<comments>http://code.davidjanes.com/blog/2008/12/18/pipe-cleaner/#comments</comments>
		<pubDate>Thu, 18 Dec 2008 23:38:21 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[djolt]]></category>
		<category><![CDATA[dqt]]></category>
		<category><![CDATA[html / javascript]]></category>
		<category><![CDATA[ideas]]></category>
		<category><![CDATA[jd]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[pipe cleaner]]></category>
		<category><![CDATA[pybm]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=372</guid>
		<description><![CDATA[I&#8217;ve been working (in my decreasing available spare time) on a project to pull together into a project called &#8220;Pipe Cleaner&#8221; all the various concepts I&#8217;ve been mentioning on this blog: Web Object Records (WORK) for API Access and object manipulation, Djolt for generating text from templates, Data/Query/Transform/Template (DQT) for transforming data and JD for [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working (in my decreasing available spare time) on a project to pull together into a project called &#8220;Pipe Cleaner&#8221; all the various concepts I&#8217;ve been mentioning on this blog: <a href="http://code.davidjanes.com/blog/category/work/">Web Object Records (WORK</a>) for API Access and object manipulation, <a href="http://code.davidjanes.com/blog/category/djolt/">Djolt</a> for generating text from templates, <a href="http://code.davidjanes.com/blog/category/dqt/">Data/Query/Transform/Template</a> (DQT) for transforming data and <a href="http://code.davidjanes.com/blog/category/jd/">JD</a> for scripting these elements together. The pieces came together this morning enough to put a demo together and here it is &#8211; <a href="http://code.davidjanes.com/examples/2008-12-18/gmaps3/">the Toronto Fires Pt II Demo</a>.</p>
<p>How, you may ask, does this differ from <a href="http://code.davidjanes.com/blog/2008/11/22/toronto-fires/">the original Toronto Fires Demo</a>? The answer is how it is put together, which we describe here.</p>
<h4>Index.dj</h4>
<p>This is the Djolt template that generates the output. The data fed to this template is generate by the JD script, described in the next section.</p>
<pre>&lt;html&gt;
&lt;head&gt;
    &lt;link rel="stylesheet" type="text/css" href="css.css" /&gt;
    {{ gmaps.js|safe }}
&lt;/head&gt;
&lt;body&gt;
&lt;div id="content_wrapper"&gt;
    &lt;div id="map_wrapper"&gt;
        {{ gmaps.html|safe }}
    &lt;/div&gt;
    &lt;div id="text_wrapper"&gt;
{% for incident in incidents %}
    &lt;div id="{{ incident.IncidentNumber }}"&gt;
        {{ incident.body_sb|safe }}
    &lt;/div&gt;
{% endfor %}
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Quite simple &#8230; as you can see, most of the data is being pulled in from elsewhere. The elsewhere is provided by the script described in the next section.</p>
<h4>Index.jd</h4>
<p>This is the script that pull all the pieces together. Note that I&#8217;m not 100% happy with the way the data is imported, I would like the geocoding to become part of this data flow too. In the next release perhaps.</p>
<p>First we pull in the &#8220;fire&#8221; module that we wrote in the previous Map examples. This is doing exactly what you think: importing a Python module. We may have to increase the security or restrict this to working with an API for general purpose use.</p>
<pre>import module:"fire";</pre>
<p>Next we define two headers &#8211; one that is going to appear in the Google Maps popup, the next that is going to appear in the sidebar. They need to be different as they refer to themselves. Note that the sidebar header &#8220;breaks&#8221; the encapsulation of Google Maps &#8211; this seems to be unavoidable. The <code>to:"fitem.head.map"</code> and <code>to:"fitem.head.sb"</code> are manipulating a WORK dictionary to store values.</p>
<p>Note also here that we&#8217;ve extended JD to accept Python multiline strings &#8211; this was unavoidable if JD was to be useful to me.</p>
<pre>set to:"fitem.head.map" value:"""
&lt;h3&gt;
&lt;a href="#{{ IncidentNumber }}"&gt;{{ AlarmLevel}}: {{ IncidentType }} on {{ RawStreet }}
&lt;/h3&gt;
""";

set to:"fitem.head.sb" value:"""
&lt;h3&gt;
{% if latitude and longitude %}
&lt;a href="javascript:js_maps.map.panTo(new GLatLng({{ latitude }}, {{ longitude }}))"&gt;*
{% endif %}
&lt;a href="#{{ IncidentNumber }}"&gt;{{ AlarmLevel}}: {{ IncidentType }} on {{ RawStreet }}
&lt;/h3&gt;
""";</pre>
<p>The next block defines the text of the body used to describe a fire incident. It follows much the same pattern as the previous block.</p>
<pre>set to:"fitem.body" value:"""
&lt;p&gt;
Alarm Level: {{ AlarmLevel }}
&lt;br /&gt;
Incident Type: {{ IncidentType }}
&lt;br /&gt;
City: {{ City }}
&lt;br /&gt;
Street: {{ Street }} ({{ CrossStreet }})
&lt;br /&gt;
Units: {{ Units }}
&lt;/p&gt;
""";</pre>
<p>This is a map: it is translating the values in <code>fire.GetGeocodeIncidents</code> into a new format and storing that in <code>incidents</code>. The format that we were are storing it in is understood by the Google Maps generating module.</p>
<p>We may rename this translate, as the word map is somewhat overloaded.</p>
<pre>map from:"fire.GetGeocodedIncidents" to:"incidents" map:{
    "latitude" : "{{ latitude }}",
    "longitude" : "{{ longitude }}",
    "title" : "{{ AlarmLevel}}: {{ IncidentType }} on {{ RawStreet }}",
    "uri" : "{{ HOME_URI }}#{{ IncidentNumber }}",
    "body" : "{{ *fitem.head.map|safe }}{{ *fitem.body|safe }}",
    "body_sb" : "{{ *fitem.head.sb|safe }}{{ *fitem.body|safe }}",
    "IncidentNumber" : "{{ IncidentNumber }}"
};</pre>
<p>Next we set up the &#8220;meta&#8221; (see <a href="http://code.davidjanes.com/blog/2008/11/11/work-web-object-records/">WORK meta description</a> if you&#8217;re not following along) for the maps. The <code>render_value:true</code> declaration makes PC interpret the templates in strings). We then call our Google Maps generating code (which are actually more Pipe Cleaners) and that gets fed to the Djolt template we first showed you. Clear? Maybe not, we&#8217;ll have more examples coming&#8230;</p>
<pre>set to:"map_meta" render_value:true value:{
    "id" : "maps",
    "latitude" : 43.67,
    "longitude" : -79.38,
    "uzoom" : -13,
    "gzoom" : 13,
    "api_key" : "{{ cfg.gmaps.api_key|otherwise:'...mykey...' }}",
    "html" : {
        "width" : "1024px",
        "height" : "800px"
    }
};

load template:"gmaps.js" items:"incidents" meta:"map_meta";
load template:"gmaps.html" items:"incidents" meta:"map_meta";</pre>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2008/12/18/pipe-cleaner/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Brief notes on SIMILE Timeline</title>
		<link>http://code.davidjanes.com/blog/2008/12/13/brief-notes-on-simile-timeline/</link>
		<comments>http://code.davidjanes.com/blog/2008/12/13/brief-notes-on-simile-timeline/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 13:01:01 +0000</pubDate>
		<dc:creator>David Janes</dc:creator>
				<category><![CDATA[demo]]></category>
		<category><![CDATA[html / javascript]]></category>

		<guid isPermaLink="false">http://code.davidjanes.com/blog/?p=345</guid>
		<description><![CDATA[SIMILE Timeline is &#8220;the Google Maps for time based events&#8221;. It used to be housed at MIT but now it&#8217;s graduated to Google Code. I&#8217;ve created an example application showing this year&#8217;s Oscar awards and a number of movies that are, umm, are not all likely to be nominated. the application source can be seen [...]]]></description>
			<content:encoded><![CDATA[<p><img style="margin: 0 0 10px 10px; float: right; border: none;" title="Timeline" src="http://code.davidjanes.com/examples/2008-12-13/timeline/timeline.png" alt="" width="64" height="64" /><a href="http://code.google.com/p/simile-widgets/wiki/Timeline">SIMILE Timeline</a> is &#8220;the Google Maps for time based events&#8221;. It used to be housed at <a href="http://simile.mit.edu/timeline/">MIT</a> but now it&#8217;s graduated to Google Code. <a href="http://code.davidjanes.com/examples/2008-12-13/timeline/">I&#8217;ve created an example application</a> showing this year&#8217;s Oscar awards and a number of movies that are, umm, are not all likely to be nominated.</p>
<ul>
<li>the application source can be seen <a href="http://code.davidjanes.com/examples/2008-12-13/timeline/index.html.txt">here</a>; it is based on this <a href="http://code.google.com/p/simile-widgets/wiki/Timeline_GettingStarted">demo</a> and <a href="http://blogmatrix.blogmatrix.com/timeline/">some work</a> I had done previously. Note:
<ul>
<li>multiple scrolling bands linked together</li>
<li>custom icons</li>
<li>custom colors</li>
</ul>
</li>
<li>we demonstrate populating the timeline widget using JSON data coded in the application; the most difficult part of putting this demo together was cutting and pasting all this data, a task we hope to make easier with our <a href="http://code.davidjanes.com/blog/category/dqt/">DQT</a> code</li>
<li>the documentation for Timeline is starting to diverge from the source code; <code>showEventText</code> is now replaced by <code>overview</code> in the band creation code</li>
<li>there&#8217;s a large number of weaknesses (still) with Timeline for dealing with arbitrary data, these may be corrected in the Javascript code but I don&#8217;t have time to go through all this
<ul>
<li>note the incorrect placement of custom icons; using Firebug to inspect the HTML, I discovered that unfortunately everything is placed using style tags so it&#8217;s difficult to correct using CSS. Ideally I would like to be able to assign classes and ID tags to everything</li>
<li>there doesn&#8217;t seem to be an obvious way to control the widths of the labels; in fact, if I reduce the band spacing in the top band, the text starts to overlap in a horrible manner</li>
<li>popup information boxes get confused when there is too little space to display information</li>
<li>when I don&#8217;t add a description to events, it uses &#8220;undefined&#8221; (see the Oscar Nominations Period)</li>
<li>date display functions are inferring more resolution (i.e. an actual time as opposed to the just the date) that I&#8217;m giving it</li>
</ul>
</li>
</ul>
<p>If anyone has corrections for me I&#8217;ll update the demo</p>
]]></content:encoded>
			<wfw:commentRss>http://code.davidjanes.com/blog/2008/12/13/brief-notes-on-simile-timeline/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

