<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Pseudointellectual Appendification</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/" />
    <link rel="self" type="application/atom+xml" href="http://www.mischievous.org/atom.xml" />
    <id>tag:www.mischievous.org,2009-06-02://1</id>
    <updated>2010-05-25T10:22:59Z</updated>
    <subtitle>Able or tending to cause annoyance, trouble, or minor injury.</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.34-en</generator>

<entry>
    <title>Experimenting with Node.js and MongoDB and Mongoose </title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2010/05/experimenting-with-nodejs-and.html" />
    <id>tag:www.mischievous.org,2010://1.11</id>

    <published>2010-05-25T10:12:13Z</published>
    <updated>2010-05-25T10:22:59Z</updated>

    <summary>Experimenting with Node.js and MongoDb and Mongoose I came across Mongoose for Node.js. It looks like a promising project but I ran into a bug as soon as I started playing with a simple counter program. The problem is in...</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="bugs" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="mongodb" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="node.js" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mongodb" label="mongodb" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mongoose" label="mongoose" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p>Experimenting with Node.js and MongoDb and Mongoose</p>

<p>I came across <a href="http://www.learnboost.com/mongoose/">Mongoose</a> for <a href="http://nodejs.org/">Node.js</a>. It looks like a promising project but I ran into a bug as soon as I started playing with a simple counter program.  The problem is in the implementation QueryPromise's atomic functions.  Here is a sample program that updates a counter. The three update forms below should all be identical, only the first seems to work with the <a href="http://github.com/LearnBoost/mongoose/commit/cb4e171ab8aca56ca1e74f1e7cbba0e77a2eaa0e">version</a> I was playing with.</p>

<pre class="brush: python">
// Simple test program to show a problem in QueryPromise
// ['inc','set','unset','push','pushAll','addToSet','pop','pull','pullAll']

var sys = require('sys')
var mongoose = require('mongoose/').Mongoose
var db = mongoose.connect('mongodb://localhost/test');

var Simple = mongoose.noSchema('test',db);
Simple.drop(); 
//should only be one....
var m = new Simple({name:'test', x:0,y:0}).save()
// these should behave the same
Simple.update({name:'test'},{'$inc':{x:1, y:1}}).execute();
Simple.update({name:'test'}).inc({x:1, y:1}).execute();
Simple.update({name:'test'}).inc({x:1}).inc({y:1}).execute();

Simple.find({name:'test'}).each(
     function (doc) {
         sys.puts(JSON.stringify(doc));
     }
).then(
    function(){ // promise (execute after query)
        Simple.close(); // close event loop
    }
);
</pre>

<p>Here is a fixed version of QueryPromise's atomic functions that place the command and arguments in the correct place.  </p>

<pre class="brush: python">
// atomic similar

  ['inc','set','unset','push','pushAll',
  'addToSet','pop','pull','pullAll'].forEach(function(cmd){
      QueryPromise.prototype[cmd] = function(modifier){
        if(this.op.name.charAt(0) != 'u') return this;
        if(!this.op.args.length) this.op.args.push({},{});
        if(this.op.args.length == 1) this.op.args.push({});
        for(i in modifier) {
          if(!(this.op.args[1]['$'+cmd] instanceof Object)) this.op.args[1]['$'+cmd] = {};
          this.op.args[1]['$'+cmd][i] = modifier[i];
        }
        return this;
      }
  });
</pre>
]]>
        

    </content>
</entry>

<entry>
    <title>Parsing City/States From User Input With Python NGram</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2010/04/parsing-citystates-from-user-i.html" />
    <id>tag:www.mischievous.org,2010://1.10</id>

    <published>2010-04-27T05:38:20Z</published>
    <updated>2010-04-27T05:44:08Z</updated>

    <summary>A friend just asked how to do city/state lookup on input strings. I&apos;ve used metaphones and Levenshtein distance in the past but that seems like over kill. Using a n-gram is a nice and easy solution easy_install ngram build file...</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="python" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ngram" label="ngram" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="python" label="python" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p>A <a href="http://www.charityblossom.org">friend</a> just asked how to do city/state lookup on input strings. I've used <a href="http://en.wikipedia.org/wiki/Metaphone">metaphones</a> and <a href="http://en.wikipedia.org/wiki/Levenshtein_distance">Levenshtein distance</a> in the past but that seems like over kill.  Using a <a href="http://en.wikipedia.org/wiki/N-gram">n-gram</a> is a nice and easy solution</p>

<ol>
<li><p>easy_install <a href="http://pypi.python.org/pypi/ngram/">ngram</a></p></li>
<li><p>build file with all the city and state names one per line, place in citystate.data Redwood City, CA Redwood, VA etc</p></li>
<li><p>Experiment ( the .2 threshold is a little lax )</p></li>
</ol>

<pre class="brush: python">
import string
import ngram
cityStateParser = ngram.NGram(
  items = (line.strip() for line in open('citystate.data')) ,
  N=3, iconv=string.lower, qconv=string.lower,  threshold=.2
)
</pre>

<p>Example:</p>

<pre class="brush: python">
cityStateParser.search('redwood')
[('Redwood VA', 0.5),
('Redwood NY', 0.5),
('Redwood MS', 0.5),
('Redwood City CA', 0.36842105263157893),
...
]
</pre>

<p>Notes: Because these are NGrams you might get overmatch when the state is part of a ngram in the city i.e. search for "washington" would yield Washington IN with a bette score than "Washington OK"</p>

<p>You might also want read <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.21.344&amp;rep=rep1&amp;type=pdf">Using Superimposed Coding Of N-Gram Lists For Efficient Inexact Matching</a> (PDF Download)</p>

<p>If this works for you, consider giving me a vote on <a href="http://stackoverflow.com/questions/2054422/get-city-state-or-zip-from-a-string-in-python/2718896#2718896">StackOverflow.com</a></p>
]]>
        

    </content>
</entry>

<entry>
    <title>Upgrading from movabletype 4 to 5 with a SQLite database</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2010/01/upgrading-from-movabletype-4-t.html" />
    <id>tag:www.mischievous.org,2010://1.9</id>

    <published>2010-01-06T18:39:35Z</published>
    <updated>2010-01-30T18:41:57Z</updated>

    <summary>I was concerned to see that SQLite was deprecated in movabletype 5.0, but I went ahead and upgraded my blog. I followed the standard procedure, copy the new version over the old version then run the mt-upgrade.cgi via the browser....</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
    <category term="moveabletype" label="moveabletype" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sqllite" label="sqllite" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="upgrade" label="upgrade" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<span class="Apple-style-span" style="font-family: 'trebuchet ms', helvetica, hirakakupro-w3, osaka, 'ms pgothic', sans-serif; "><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">I was concerned to see that SQLite was deprecated in movabletype 5.0, but I went ahead and upgraded my blog. I followed the standard procedure, copy the new version over the old version then run the mt-upgrade.cgi via the browser. The upgrade script never made it to migrating the database. When this happened I just used the "Upgrade a large database" instructions</p><pre style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><code style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">    $ export MT_HOME=/var/local/mv
$ cd $MT_HOME
$ perl  ./tools/upgrade --name superuser
upgrade -- A command line tool for upgrading the schema for Movable Type.
    * Upgrading database from version 4.0070.
    * Upgrading table for Website records...
    * Upgrading table for MT::Entry::Summary records...
    * Upgrading table for entry_rev records...
    * Upgrading table for Entry records...
    * Upgrading table for Asset Placement records...
    * Upgrading table for Session records...
    * Upgrading table for MT::Author::Summary records...
    * Upgrading table for User records...
    * Upgrading table for template_rev records...
    * Upgrading table for Template records...
    * Upgrading table for Permission records...
    * Upgrading table for Comment records...
    * Rebuilding permissions...
    * Rebuilding permissions... (100%)
    * Updating existing role name...
    * Populating new role for website...
    * Migrating mtview.php to MT5 style...
    * Assigning new system privilege for system administrator...
    * Assigning to  jason...
    * Updating existing role name...
    * Populating new role for theme...
    * Upgrading Asset path informations...
    * Classifying blogs...
    * Classifying blogs... (100%)
    * Merging dashboard settings...
    * Merging dashboard settings... (100%)
    * Migrating existing 1 blog into websites and its children...
    * Generated a website http://mischievous.org/
    * Moved blog Pseudointellectual Appendification (http://www.mischievous.org/) under website mischievous.org
    * Creating new template: 'Comment Listing'.
    * Database has been upgraded to version 5.0016.
Upgrade complete!</code></pre></span>]]>
        
    </content>
</entry>

<entry>
    <title>How to Backup California Mathematics Grade 4 PDFs to Paper</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2009/10/how-to-backup-california-mathe.html" />
    <id>tag:www.mischievous.org,2009://1.8</id>

    <published>2009-10-13T04:03:29Z</published>
    <updated>2009-10-13T04:13:49Z</updated>

    <summary>My school sent home a set of 3 CD&apos;s with circa Glencoe StudentWorks software from 2007. This software consists of a flash application that launches Adobe Acrobat version 7 to display PDF the PDF content of the California Mathematics Grade...</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="education" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="backup" label="backup" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="password" label="password" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="pdf" label="pdf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="print" label="print" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="protected" label="protected" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p>My school sent home a set of 3 CD's with circa Glencoe StudentWorks software from 2007.
This software consists of a flash application that launches Adobe Acrobat version 7 to display
PDF the PDF content of the California Mathematics Grade 4 workbooks.  Children are 
expected to complete homework assignments using this software.  My primary operating system
is Mac OS X v10.6 Snow Leopard, the application "Student Works OSX" is a PowerPC application 
and would require Rosetta to be installed to run.</p>

<p>Thankfully, the PDFs are on the CD 
and you do not need to run the application to see the content, just navigate to 
<strong>/Volumes/CA Math 4/support/PDF/docs</strong> and you will find the PDF for each individual chapter. <br />
On Mac or Windows, there is no need to install or run any application from the disc, If you
are running Windows, download the latest Acrobat, don't install the antiquated version on the disc.</p>

<p>Printing is another matter, you can't.  The chapters are password print protected. I'm not
a lawyer but I read the standard shrink wrap licensing agreement that came with the software
and here is what I found:</p>

<blockquote>
  <p>COPIES. Copies can be made only as authorized above
  in machine readable form. Print copies of Software code
  are not authorized. All copyright and trademark notices
  must remain on all copies. All copies must be faithful
  reproductions. You are solely responsible for the content,
  quality and operation of all Software copies. Certain
  Software programs may be "copy protected" by special
  encryption coding that prevents copying or 
  printing-out content</p>
</blockquote>

<p>And</p>

<blockquote>
  <p>You may also make one (1) back- up copy of the Software
  for archival purpose</p>
</blockquote>

<p>Great, I choose to backup the PDF portions of the "software" by printing on
paper.  Here is my "backup" program, you just need GhostScript from macports.</p>

<pre class="brush: python">

    #!/bin/bash -x
    for i in "$@"; do
        NAME=`basename "$i"`
        gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile="$NAME" -c .setpdfwrite -f "$i"
        lpd -d "SCX_4500" "$NAME"
        rm $NAME
    done

</pre>
]]>
        

    </content>
</entry>

<entry>
    <title>How To Use Your Redwood City Public Library Card to Access Safari Books Online</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2009/08/how-to-use-your-redwood-city-p.html" />
    <id>tag:www.mischievous.org,2009://1.7</id>

    <published>2009-08-07T17:24:52Z</published>
    <updated>2009-08-07T17:41:38Z</updated>

    <summary>If you live in San Mateo County you can use your Peninsula Library System Card to access Safari Books Online. If you manage to find link on the plsinfo.org website you will find that the proxy url is incorrect. Here...</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="library" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="library" label="Library" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="safari" label="Safari" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p>If you live in San Mateo County you can use your Peninsula Library System Card to access Safari Books Online.</p>

<p>If you manage to find link on the plsinfo.org website you will find that the proxy url is incorrect. <br />
Here is the correct link <a href="http://ezproxy.plsinfo.org:2048/login?url=http://proquest.safaribooksonline.com">Safari Books Online</a>, you need your library card.</p>

<p>Read away.</p>

<p>You can also see a list of all the <a href="http://ezproxy.plsinfo.org:2048/menu">resources you can access via your library card</a>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>SocialCurrent, Become a Cohesive Force for Change</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2009/07/socialcurrent-become-a-cohesiv.html" />
    <id>tag:www.mischievous.org,2009://1.6</id>

    <published>2009-07-27T22:42:01Z</published>
    <updated>2009-07-27T22:48:00Z</updated>

    <summary>A friend just launched his website, SocialCurrent. The idea brings the Tao Te Ching to mind. All things spring up and there is not one which declines to show itself. They grow and there is no claim made for their...</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="social responsibility" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="change" label="change" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="socialcurrent" label="socialcurrent" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p>A friend just launched his website, <a href="http://www.socialcurrent.org">SocialCurrent</a>.  The idea brings the Tao Te Ching to mind. </p>

<p>All things spring up and there is not one which declines to show itself. <br />
They grow and there is no claim made for their ownership. <br />
The go through their processes and there no expectation of a reward for their results. <br />
The work is accomplished, and there is no resting in it as an achievement. <br />
The work is done, but how no one can see. 'Tis this that makes the power not cease to be.  </p>

<p>Everyday we do things in our daily life that we perceive as socially responsible, yet our actions sometimes invisible. These invisible things add up and the actions of one person can truly make a difference.  </p>
]]>
        

    </content>
</entry>

<entry>
    <title> mdworker Unable to use font: no glyphs present</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2009/06/mdworker-unable-to-use-font-no.html" />
    <id>tag:www.mischievous.org,2009://1.4</id>

    <published>2009-06-04T21:08:24Z</published>
    <updated>2009-06-04T21:15:33Z</updated>

    <summary>Running Apple Mac OSX, and your system.log is filling up with mdworker[473]: Unable to use font: no glyphs present. /System/Library/Frameworks/ApplicationServices.framework /Frameworks/ATS.framework/Support/ATSServer[474]: Serious problems were found in font data while activating it. /System/Library/Frameworks/ApplicationServices.framework /Frameworks/ATS.framework/Support/ATSServer[474]: You may encounter drawing or printing problems....</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="bugs" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="apple" label="apple" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="hadoop" label="hadoop" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mdworker" label="mdworker" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="osx" label="osx" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p>Running Apple Mac OSX, and your system.log is filling up with</p>

<p>mdworker[473]: Unable to use font: no glyphs present.</p>

<p>/System/Library/Frameworks/ApplicationServices.framework /Frameworks/ATS.framework/Support/ATSServer[474]: Serious problems were found in font data while activating it.</p>

<p>/System/Library/Frameworks/ApplicationServices.framework /Frameworks/ATS.framework/Support/ATSServer[474]: You may encounter drawing or printing problems.</p>

<p>Well, it could be Spotlight trying to index a bad PDF file.  To find the offending file with use lsof and the process id of the mdworker process</p>

<pre>
  lsof -p 473
</pre>

<p>In my case it was a PDF from the hadoop 20.0 release</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Cascading and Coroutines</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2009/06/cascading-and-coroutines.html" />
    <id>tag:www.mischievous.org,2009://1.3</id>

    <published>2009-06-02T03:23:37Z</published>
    <updated>2009-06-02T07:07:59Z</updated>

    <summary>Cascading looks quite interesting. Here is a python program that does something similar to the Technical Overview seen main in the python program. #!/usr/bin/env python # encoding: utf-8 import sys def input(theFile, pipe): &quot;&quot;&quot; pushes a file a line at...</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="python" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cascading" label="cascading" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="coroutine" label="coroutine" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="python" label="python" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p><a href="http://www.cascading.org/">Cascading</a> looks quite interesting.   Here is a python program that does something similar to the <a href="http://www.cascading.org/documentation/overview.html">Technical Overview</a> seen <strong><code>main</code></strong> in the python program.  </p>

<pre class="brush: python">
    #!/usr/bin/env python
    # encoding: utf-8
    import sys

    def input(theFile, pipe):
        """
        pushes a file a line at a time to a coroutine pipe
        """
        for line in theFile:
            pipe.send(line)
        pipe.close()

    @coroutine
    def extract(expression, pipe, group = 0):
        """
        extract the group from a regex
        """
        import re
        r = re.compile(expression)
        while True:
            line = (yield)
            match = r.search(line)
            if match:
                pipe.send(match.group(0))

    @coroutine
    def sort(pipe):
        """
        sort the input on a pipe
        """
        import heapq
        heap = []
        try:
            while True:
                line = (yield)
                heapq.heappush(heap, line)
        except GeneratorExit:
            while heap:
                pipe.send(heapq.heappop(heap))

    @coroutine
    def group(groupPipe, pipe):
        """
        sends consectutive matching lines from pipe to groupPipe
        """
        cur = None
        g = None
        while True:
            line = (yield)
            if cur is None:
                g = groupPipe(pipe)
            elif cur != line:
                g.close()
                g = groupPipe(pipe)

            g.send(line)
            cur = line

    @coroutine
    def uniq(pipe):
        """
        implements uniq -c
        """
        lines = 0
        try:
            while True:
                line = (yield)
                lines += 1
        except GeneratorExit:
            pipe.send('%s\t%s' % (lines, line))

    @coroutine
    def output(theFile):
        while True:
            line = (yield)
            theFile.write(line + '\n')

    def main():
        input(sys.stdin,
            extract( r'^([^ ]+)',
                sort(
                    group( uniq,
                        output(sys.stdout)
                    )
                )
            )
        )

    if __name__ == '__main__':
        main()
</pre>

<p>You can achieve the same results with the unix command line:</p>

<pre><code>cat  access.log | cut -d ' ' -f 1 | sort | uniq -c
</code></pre>
]]>
        

    </content>
</entry>

<entry>
    <title>Python Coroutines and Twitter</title>
    <link rel="alternate" type="text/html" href="http://www.mischievous.org/2009/06/python-coroutines-and-twitter.html" />
    <id>tag:www.mischievous.org,2009://1.2</id>

    <published>2009-06-01T22:54:25Z</published>
    <updated>2009-06-02T07:41:11Z</updated>

    <summary>Reading http://www.dabeaz.com/coroutines/ and thought this was a natural for a twitter client. Here is a pretty simple version that just prints the public timeline every 60 seconds. Next, up removing the time.sleep and scheduling the followStatus function as a task...</summary>
    <author>
        <name>Jason Culverhouse</name>
        <uri>http://www.mischievous.org/jason/</uri>
    </author>
    
        <category term="python" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="coroutine" label="coroutine" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="python" label="python" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="twitter" label="twitter" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.mischievous.org/">
        <![CDATA[<p>Reading <a href="http://www.dabeaz.com/coroutines/">http://www.dabeaz.com/coroutines/</a> and thought this was a natural for a twitter client. Here is a pretty simple version that just prints the public timeline every 60 seconds.  Next, up removing the time.sleep and scheduling the followStatus function as a task so I can follow more than one stream at a time.</p>

<pre class="brush: python">
    #!/usr/bin/env python
    # encoding: utf-8
    import time
    import twitter

    def coroutine(func):
        """
        A decorator function that takes care of starting a coroutine
        automatically on call.

        see: http://www.dabeaz.com/coroutines/
        """
        def start(*args,**kwargs):
            cr = func(*args,**kwargs)
            cr.next()
            return cr
        return start

    @coroutine
    def statusPrinter():
        """
        Just prints twitter status messages to the screen
        """
        while True:
             status = (yield)
             print status.id, status.user.name, status.text

    def followStatus(twitterGetter, target, timeout = 60):
        """
        Follows a twitter status message that takes a since_id
        """
        since_id = None
        while True:
            statuses = twitterGetter(since_id=since_id)
            if statuses:
                # pretty sure these are always in order
                since_id = statuses[0]
                for status in statuses:
                    target.send(status)
            # twitter caches for 60 seconds anyway
            time.sleep(timeout)

    def main():
        api = twitter.Api()
        followStatus(api.GetPublicTimeline, statusPrinter())

    if __name__ == '__main__':
        main()
 </pre>   
]]>
        

    </content>
</entry>

</feed>
