<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <title>Let’s Discuss the Matter Further</title>
    <link>http://rhodesmill.org/brandon</link>
    <description>Your Blog's short description</description>
    <pubDate>Thu, 19 Jan 2012 00:48:19 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Changed rules for Picasa tag searches</title>
      <link>http://rhodesmill.org/brandon/2010/picasa-tag-searches/</link>
      <pubDate>Tue, 15 Jun 2010 12:56:09 EDT</pubDate>
      <category><![CDATA[web notes]]></category>
      <category><![CDATA[computing]]></category>
      <guid>http://rhodesmill.org/brandon/?p=360</guid>
      <description>Changed rules for Picasa tag searches</description>
      <content:encoded><![CDATA[
<p>
  Well, drat.
</p>
<p>
  Several images disappeared from the
  <a href="http://www.ourfreshworld.com/">Our Fresh World</a>
  green-building web site
  because Google changed their Picasa API recently —
  and I must not be subscribed to the proper mailing list or blog
  to have been warned ahead of time.
  Where are incompatible Google API tweaks announced?
</p>
<div class="dropshadow alignright"> 
  <a><img border="0" src="http://rhodesmill.org/brandon/static/2010/solar-power.jpg"/></a>
</div> 
<p>
  The site owner and his photographer use
  <a href="http://picasaweb.google.com/">Picasa web albums</a>
  to upload, edit, and maintain their image collection.
  They simply give special tags to their favorite photos,
  and my application code then knows
  that it is supposed to display those photos on the web site.
  I almost used <a href="http://flickr.com/">Flickr</a>
  for this application,
  both because I am an avid Flickr user myself
  and because I consider its web interface more usable.
  But, perhaps predictably, Picasa had the much stronger search API —
  whereas you can either ask Flickr for the photos in a particular set,
  <i>or</i> ask for all of someone's photos that share a particular tag,
  Picasa lets you can combine the two queries
  and ask for only the photos that are in a particular set
  <i>and</i> that also share a specific tag.
  And since search is what attaches pictures to this web site,
  Picasa was my choice.
</p>
<p>
  All was going well,
  with each page getting populated by searches like:
</p>
<pre>
http://picasaweb.google.com/data/feed/api/user/<i>name</i><br/>?kind=photo&tag=solar-power
</pre>
<p>
  Then I received an email from the site owner,
  complaining that many of the photographs had disappeared!
  After seeing some complaints in the Picasa forums
  about recent versions of the user interface
  treating certain “special characters” in tags as spaces instead,
  I suddenly wondered whether the hyphen in several of our tags
  (like the “solar-power” tag in the URL above)
  was the cause of our trouble.
  I adjusted my code so that this search became:
</p>
<pre>
http://picasaweb.google.com/…?kind=photo&tag=solar+power
</pre>
<p>
  And, voilà, the images returned and were again visible!
  Does anyone know what forum or blog I should have been following
  to be informed of this critical change by Google?
  It is dismaying to have a site break in front of a customer
  when the very reason that I chose a Google product
  was because of their powerful API for integrating my application.
</p>]]></content:encoded>
    </item>
    <item>
      <title>Installing &quot;lxml&quot; for Python under your WebFaction account</title>
      <link>http://rhodesmill.org/brandon/2009/installing-lxml-on-webfaction/</link>
      <pubDate>Sat, 01 Aug 2009 18:03:34 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[web notes]]></category>
      <category><![CDATA[computing]]></category>
      <guid>http://rhodesmill.org/brandon/?p=196</guid>
      <description>Installing &quot;lxml&quot; for Python under your WebFaction account</description>
      <content:encoded><![CDATA[
<p>
  Well, drat.
</p>
<p>
  Thanks to more than an hour of work today,
  I have a pretty list of a few dozen commands
  that make it easy for a WebFaction account holder
  to install the powerful
  <a href="http://codespeak.net/lxml/">lxml</a> Python package
  for parsing HTML and XML under their hosting account.
  You can read Ian Bicking's wonderful blog post
  <a href="http://blog.ianbicking.org/2008/12/10/lxml-an-underappreciated-web-scraping-library/"
     >“lxml: an underappreciated web scraping library”</a>
  for more information on why you want to be using lxml
  instead of any of its alternatives.
</p>
<p>
  So, why do I say “drat”?
</p>
<p>
  First,
  because I just tried out my instructions on another
  of my WebFaction accounts,
  and there the extra steps weren't even necessary;
  this other server of theirs
  already had lxml's dependencies installed!
  I suppose, had I been a bit more patient, that
  <a href="http://forum.webfaction.com/viewtopic.php?id=2695"
     >this support ticket that I glanced over this morning</a>
  would have inspired me to ask WebFaction
  to install the libraries lxml needs
  on the server where I myself was working.
  But it felt like some sort of offense against symmetry
  to rely on something that WebFaction doesn't install everywhere,
  and I was perhaps just in too big of a hurry.
  Which, of course, cost more time in the end.
</p>
<p>
  The other reason I say “drat” is because,
  now that I look at Ian's post again after all these months,
  I see that he has instructions for making the package
  install its own dratted copies of the system libraries it needs!
  Too bad that
  <a href="http://codespeak.net/lxml/installation.html"
     >lxml's own installation instructions</a>
  omit this crucial piece of information.
</p>
<p>
  How typical, and how predictable.
  It turns out that I just needed to listen to Ian Bicking more carefully.
  How often we fail to do that,
  as individuals and as a Python community.
  Listen to Ian Bicking, everyone.
  Listen.
</p>
<!--more-->
<p>
  In the meantime,
  here are some successful and unsuccessful ways
  of installing lxml under your WebFaction account.
  Consider the following to be a set of choose-your-own adventure
  scenarios.
</p>
<ul>
  <li>
    <p>
      If the WebFaction host your account lives on
      <b>already has libxml and libxslt installed</b>,
      then installation is simple:
    </p>
    <pre
>$ easy_install lxml
Searching for lxml
Reading http://pypi.python.org/simple/lxml/
...
<b>Finished processing dependencies for lxml</b>
</pre>
  <li>
    <p>
      If your WebFaction host <b>lacks libxml</b>,
      but you <b>listen to Ian Bicking</b>
      and <b>download the source code yourself</b>,
      then your install will succeed:
    </p>
    <pre
>$ wget <a href="http://pypi.python.org/packages/source/l/lxml/lxml-2.2.2.tar.gz"
          >http://pypi.python.org/.../lxml-2.2.2.tar.gz</a>
$ tar xfz lxml-2.2.2.tar.gz
$ cd lxml-2.2.2
$ STATIC_DEPS=true python setup.py install
...
<b>Finished processing dependencies for lxml==2.2.2</b></pre>
  </li>
  <li>
    <p>
      If your WebFaction host <b>lacks libxml</b>,
      but you <b>listen to Ian Bicking</b>,
      but you <b>rely on easy_install to fetch the package</b>,
      then your install will <b>fail</b>
      because it tries building inside of a temporary directory
      that, on WebFaction, you apparently cannot access:
    </p>
    <pre
>$ STATIC_DEPS=true easy_install lxml
Searching for lxml
Reading http://pypi.python.org/simple/lxml/
...
Running "./configure --without-python --disable-dependency-tracking
 --disable-shared --prefix=/tmp/easy_install-81ufo5/lxml-2.2.2/buil
d/tmp/libxml2" in build/tmp/libxml2-2.7.3
<b>error: Permission denied</b></pre>
  </li>
  <li>
    <p>
      If your WebFaction host <b>lacks libxml</b>,
      and you <b>fail to listen to Ian Bicking</b>,
      then you can at least install lxml and its dependencies manually
      using the following commands,
      as I worked out this morning.
      The trick is that instead of trying to tell <tt>setup.py</tt>
      where you have installed the libraries
      by using <tt>CC=</tt> at the beginning of the command line
      or something like that,
      you need to make sure that the special command <tt>xslt-config</tt>
      is on your path somewhere:
    </p>
    <pre
>$ cd ~
$ mkdir usr
$ mkdir usr/src
$ cd usr/src
$ wget <a href="ftp://xmlsoft.org/libxml2/libxml2-2.7.3.tar.gz"
           >ftp://xmlsoft.org/.../libxml2-2.7.3.tar.gz</a>
$ wget <a href="ftp://xmlsoft.org/libxml2/libxslt-1.1.24.tar.gz"
          >ftp://xmlsoft.org/.../libxslt-1.1.24.tar.gz</a>
$ tar xfz libxml2-2.7.3.tar.gz
$ tar xfz libxslt-1.1.24.tar.gz
$ cd libxml2-2.7.3
$ ./configure --prefix ~/usr
$ make install
$ cd ..
$ cd libxslt-1.1.24
$ ./configure --prefix ~/usr
$ make install
$ cd ..
$ PATH=$HOME/usr/bin:$PATH
$ wget <a href="http://pypi.python.org/packages/source/l/lxml/lxml-2.2.2.tar.gz"
          >http://pypi.python.org/.../lxml-2.2.2.tar.gz</a>
$ tar xfz lxml-2.2.2.tar.gz
$ cd lxml-2.2.2
$ python setup.py install
...
<b>Finished processing dependencies for lxml==2.2.2</b></pre>
  </li>
</ul>
<p>
  But, as I mentioned, Ian's technique is faster. :-)
</p>]]></content:encoded>
    </item>
    <item>
      <title>New Year&#039;s meme: What are the oldest files in your home directory?</title>
      <link>http://rhodesmill.org/brandon/2009/new-years-meme/</link>
      <pubDate>Thu, 01 Jan 2009 14:27:57 EST</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[web notes]]></category>
      <category><![CDATA[computing]]></category>
      <guid>http://rhodesmill.org/brandon/?p=31</guid>
      <description>New Year&#039;s meme: What are the oldest files in your home directory?</description>
      <content:encoded><![CDATA[
<p>
Celebrate the new year with a blog post
discussing the oldest files
that are still sitting somewhere beneath your home directory!
The procedure is simple:
</p>
<ol>
<li>Run the following script in your home directory.
(You might want to use <i>less</i> to read the output.)</li>
<li>Ignore files whose date does not reflect your own activity.</li>
<li>List the oldest files in a blog post and discuss!</li>
</ol>

<div class="pygments_murphy syntax_highlight"><pre><span class="c">#!/usr/bin/env python</span><br/><span class="sd">&quot;&quot;&quot;Print last-modified times of files beneath &#39;.&#39;, oldest first.&quot;&quot;&quot;</span><br/><span class="kn">import</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">os.path</span><span class="o">,</span> <span class="nn">time</span><br/><span class="n">paths</span> <span class="o">=</span> <span class="p">(</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="n">f</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="n">ds</span><span class="p">,</span><span class="n">fs</span><span class="p">)</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="s">&#39;.&#39;</span><span class="p">)</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">fs</span> <span class="p">)</span><br/><span class="k">for</span> <span class="n">mtime</span><span class="p">,</span> <span class="n">path</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span> <span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">lstat</span><span class="p">(</span><span class="n">p</span><span class="p">)</span><span class="o">.</span><span class="n">st_mtime</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">paths</span> <span class="p">):</span><br/>    <span class="k">print</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">&quot;%Y-%m-</span><span class="si">%d</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">localtime</span><span class="p">(</span><span class="n">mtime</span><span class="p">)),</span> <span class="n">path</span><br/></pre></div>


<p>
Only include files whose last-modified time
is a date on which you really touched the file.
The file's time should neither result from an error
(a few files beneath my own home directory
have an incorrect date of 1970-01-01),
nor from unpacking someone else's archive
that has old files inside of it.
For example,
I myself have excluded
the following pair of nearly 17-year-old files
because their dates reflect their age
inside of the Python 3.0 source archive,
instead of the actual moment last month
when they became part of my home directory:
</p>
<pre>
1992-03-02 ./src/Python-3.0/Demo/scripts/wh.py
1992-03-02 ./src/Python-3.0/Tools/scripts/dutree.doc
</pre>
<p>
But there is no requirement that the actual <i>content</i>
of each file you list be your own.
Whether you wrote the file yourself long ago,
or downloaded it from some ancient and forgotten FTP site,
you have a story to share!
</p>
<p>
Within the rules given above,
here are the oldest files beneath my own home directory:
</p>
<!--more-->
<pre>
# My oldest five files!
# (The links return their content.)

1989-05-17 ./archive/unixpc/cee/crobots/<a href="/brandon/static/2009/BCRMAD.R.txt">BCRMAD.R</a>
1989-05-17 ./archive/unixpc/cee/crobots/<a href="/brandon/static/2009/BCRONE.R.txt">BCRONE.R</a>
1990-01-18 ./archive/unixpc/ref/<a href="/brandon/static/2009/train">train.gz</a>
1990-01-18 ./archive/unixpc/ref/<a href="/brandon/static/2009/xmas">xmas.gz</a>
1990-05-18 ./archive/unixpc/save/Rhodes/<a href="/brandon/static/2009/treasure">treasure</a>
</pre>
<p>
You can see that these files were moved, long ago,
into an archive directory for files
that are no longer part of an active project.
These files all date from the era
when my home directory was hosted
on the <span class="sc">Unix</span> PC which my father,
a Bell Laboratories engineer,
brought home in the 1980s as our personal computer.
</p>
<p>
We should start with the zipped files from January 1990,
since they actually contain even older content,
from December 1987 —more than twenty years ago!
My father received them as Christmas greetings
from fellow engineers at the Labs.
You can view
<a href="/brandon/static/2009/xmas"><tt>xmas</tt></a>
right in your browser,
since it is a simple ASCII-art holiday greeting
(the name “Merrimack Valley” at the bottom
refers to the particular Bell Labs location
at which my father worked).
Viewing
<a href="/brandon/static/2009/train"><tt>train</tt></a>
is more difficult, since it contains a VT-100 animation
that will display much too quickly
if you dump the file to a modern terminal.
Instead, download the file and use this Python program
to display it at a more traditional speed;
you might want to light a candle and play some Christmas music
while the animation is displaying:
</p>

<div class="pygments_murphy syntax_highlight"><pre><span class="c">#!/usr/bin/env python</span><br/><span class="sd">&quot;&quot;&quot;Display the &#39;train&#39; file, slowly.&quot;&quot;&quot;</span><br/><span class="kn">import</span> <span class="nn">sys</span><span class="o">,</span> <span class="nn">time</span><br/><span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;train&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">():</span><br/>    <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">c</span><span class="p">)</span><br/>    <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span><br/>    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.0</span><span class="o">/</span><span class="mf">9600.0</span><span class="p">)</span> <span class="c"># (drat, really sleeps 0.01s)</span><br/></pre></div>


<p>
Though Dad probably retained the files only through the Christmas season,
I was fascinated by watching them
scroll silently across the black screen
in glowing, green, phosphoric characters
that seemed to leave trails behind them like shooting stars,
and so I kept the files
long after many subsequent Christmases had come and gone.
</p>
<p>
The other three files are all plain-text files,
and are all of my own making.
The <a href="/brandon/static/2009/BCRMAD.R.txt"><tt>BCRMAD.R</tt></a>
and <a href="/brandon/static/2009/BCRONE.R.txt"><tt>BCRONE.R</tt></a>
programs were experiments in
<a href="http://en.wikipedia.org/wiki/Crobots">the old
<span class="sc">crobots</span> game</a>,
where you wrote small C-language programs
to control robots that drove around on the screen
and shot at each other.
The names seem to refer to the fact
that the first file simulates a “mad bull”
that drives straight at targets
shooting as fast as it can,
while the second program always takes “one shot” at a target
then flees to another location on the screen.
This would have been one of my very first forays into C programming —
perhaps my very first —
and so the algorithms are, I must admit,
not exactly pinnacles of sophistication.
</p>
<p>
The last file is named
<a href="/brandon/static/2009/treasure"><tt>treasure</tt></a>,
and it is, indeed, a real treasure of a file
to have discovered this New Year's morning!
It is my long-lost account,
carefully annotated with the venerable <tt>mm</tt> macro package
(as you can see from the <i>troff</i> include directive
on the first line),
of the day in early 1990
when I discovered buried treasure
that my father had hidden as a child on my grandparent's property!
I actually saw the “treasure” last week
(an ancient coffee can with old toys inside)
sitting on a shelf when I visited my grandmother on Christmas Day.
I will have to pull it down from the shelf
and put some pictures on Flickr, along with excerpts
from this long-lost story of its discovery!
</p>
<p>
In the meantime: what are the oldest files under <i>your</i>
home directory?
</p>
]]></content:encoded>
    </item>
    <item>
      <title>Rise and Fall of the Two Waldos</title>
      <link>http://rhodesmill.org/brandon/2008/rise-and-fall-of-the-two-waldos/</link>
      <pubDate>Wed, 05 Nov 2008 09:41:01 EST</pubDate>
      <category><![CDATA[web notes]]></category>
      <guid>http://rhodesmill.org/brandon/?p=24</guid>
      <description>Rise and Fall of the Two Waldos</description>
      <content:encoded><![CDATA[
<p>
I am experiencing my Flickr photostream in an entirely new way
thanks to the tools they introduced this year
for monitoring the traffic received by individual photographs.
The old, static parts of my photostream suddenly look dynamic:
I can see the <i>rate</i>
at which each old photo is continuing to attract viewers.
On October 17th, for example, I
was stunned to discover that the perennial favorite
<a href="http://www.flickr.com/photos/brandonrhodes/40609212/">Harry
Potter Lunchbox</a> had, over the previous day,
received <i>fewer</i> views than the perpetually distant second,
<a href="http://www.flickr.com/photos/brandonrhodes/41593686/">“My
Shirt”</a>
(both taken at Dragon*Con 2005).
Here is Flickr's graph of how “My Shirt” fared over the month of
October, with my mouse over October 17th
to highlight the day on which I first noticed its growing popularity:
</p>

<div class="caption">
<a href="/brandon/static/2008/my-shirt-stats.png">
<img src="/brandon/static/2008/my-shirt-stats-thumb.png"
     alt="graph of the photograph popularity" /></a>
The rise and fall of the popularity of
<a href="http://www.flickr.com/photos/brandonrhodes/41593686/">“My
Shirt”</a>
over the four weeks from 5 October through 1 November.
</div>

<p>
And by drilling down into the list of “Referrers” beneath the graph,
I was even able to discover the source of its brief popularity!
As Halloween approached,
people were doing hundreds of
<a href="http://images.google.com/imghp?tab=wi">Google Image</a>
searches
for “waldo costume”, “where's waldo costume”,
and “where's waldo shirt”,
which brought them straight to my image.
As you can see in the above graph,
the swelling interest did not peak until Halloween itself,
after which the photo plummeted back to its more typical popularity
of one or two dozen views per day.
</p>

<p>
All sorts of gems are hidden in the statistics,
waiting to be discovered.
For example,
it was very satisfying to learn
that <a href="http://images.search.yahoo.com/">Yahoo! Image Search</a>
considers my wedding photograph
<a href="http://www.flickr.com/photos/brandonrhodes/79478143/">A
Grandfather in Attendance</a>
to be the most important “grandfather” image on the entire web.
Behind every statistic is a story about how people find,
and why they wind up visiting, each of my photos.
Hopefully the fun of watching my old photographs
will not distract me from taking some new ones!
</p>]]></content:encoded>
    </item>
    <item>
      <title>The idea of a term paper</title>
      <link>http://rhodesmill.org/brandon/2008/the-idea-of-a-term-paper/</link>
      <pubDate>Sat, 25 Oct 2008 12:14:01 EDT</pubDate>
      <category><![CDATA[web notes]]></category>
      <guid>http://rhodesmill.org/brandon/?p=23</guid>
      <description>The idea of a term paper</description>
      <content:encoded><![CDATA[
<p>
Displaying their usual talent for excerpt,
the folks at <a href="http://aldaily.com">Arts &amp; Letters Daily</a>
directed my attention to a recent article
in <a href="http://www.thesmartset.com/">The Smart Set</a>
with this intriguing summary of its contents:
</p>

<blockquote><p><b>Term paper mill.</b> Need $100 by Friday to keep the lights on? No sweat, if you’re a writer. Plenty of kids need ten pages on Hamlet by Thursday... <a href="http://www.thesmartset.com/article/article10100801.aspx">more»</a></p></blockquote>

<p>
The article,
entitled “<a href="http://www.thesmartset.com/article/article10100801.aspx"
 >Term Paper Artist</a>”,
alternates between hilarity and poignancy
as its author shares his adventures
writing hundreds of term papers for hire.
But near the end,
his tone suddenly becomes serious
as he turns to the question of <i>why</i> so many students
are unable to write term papers of their own.
He thinks that the reason is important enough
to stand alone in his article as a one-sentence paragraph.
Here is his preceding paragraph, and then the zinger:
</p>

<blockquote>
<p>It's not that I never felt a little skeevy writing
papers. Mostly it was a game, and a way to subsidize my more interesting
writing. Also, I've developed a few ideas of my own over the years. I
don't have the academic credentials of composition experts, but I doubt
many experts spent most of a decade writing between one and five term
papers a day on virtually every subject. I know something they don't
know; I know why students don't understand thesis statements,
argumentative writing, or proper citations.
</p>
<p>
It's because students have never read term papers.
</p>
</blockquote>

<p>
That is his diagnosis:
students never see what term papers are <i>supposed</i> to look like,
and so they have no idea how to produce them.
</p>

<p>
As he continued on,
ridiculing the idea that students
can produce something of which they are never once shown a good example,
I realized that his argument was exactly the same
as the one I made in my recent post
<a href="http://rhodesmill.org/brandon/2008/reading-code-curriculum/"
 >Reading Code: A Computer Science Curriculum</a>:
that the production of any kind of literature,
whether an essay in college or an elaborate routine in a computer program,
is an essentially imitative act.
Without being shown excellent examples
from the genre they are expected to produce,
students are left in the dark about what,
exactly, they are trying to generate —
and, more often than not, will fail.
They are never even given the opportunity
to demonstrate whether they do, in fact, lack the capacity to create,
because they are never shown the goal
towards which they are supposed to be striving.
</p>]]></content:encoded>
    </item>
    <item>
      <title>PyEphem 3.7.2.4, now on Launchpad!</title>
      <link>http://rhodesmill.org/brandon/2008/pyephem-3724-now-on-launchpad/</link>
      <pubDate>Sat, 14 Jun 2008 13:39:57 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[pyephem]]></category>
      <category><![CDATA[web notes]]></category>
      <category><![CDATA[computing]]></category>
      <guid>http://rhodesmill.org/brandon/?p=19</guid>
      <description>PyEphem 3.7.2.4, now on Launchpad!</description>
      <content:encoded><![CDATA[
<p><img style="float: right;"
 src="http://rhodesmill.org/pyephem/_static/pyephem-logo-short.png"
 alt="PyEphem logo" />
I have decided to give my
<a href="http://rhodesmill.org/pyephem">PyEphem
astronomy library for Python</a>
a public source code repository,
an open forum for user questions,
and a bug tracker where my users
can see the progress of their bug reports out in the open
rather than having them scattered across our email inboxes.
To accomplish all of this,
I simply registered PyEphem with
<a href="http://launchpad.net/">Launchpad</a>,
a site built to host software projects
that is already used by several projects for which I have great respect.
</p>

<p>
Because users might become confused
now that PyEphem is spread across <i>three</i> web sites —
the home page is here at rhodesmill.org,
releases are posted over at the
<a href="http://www.python.org/pypi">Python Package Index</a>,
and, again, the development project is now hosted at Launchpad —
I have completely
<a href="http://rhodesmill.org/pyephem">redesigned the PyEphem home
page</a> with the goal of making the three-site distinction
clear, coherent, and easy to navigate.
The new home page and documentation
are generated by the wonderful
<a href="http://sphinx.pocoo.org/">Sphinx documentation engine</a>,
and I am still thrilled about how pretty my code samples look
(check out the one on the PyEphem home page!)
now that Sphinx is coloring them in with the renowned
<a href="http://pygments.org/">Pygments</a> system.
</p>

<p>
I have simultaneously released a new version of PyEphem
that includes the new Sphinx-based documentation,
along with several important fixes to the software itself.
From now on,
rather than cluttering my own blog
with every minor version of PyEphem that I might release,
fans of the software should visit its
<a href="https://launchpad.net/pyephem/+announcements">News and
announcements</a> page on Launchpad
and subscribe themselves to its
<a href="http://feeds.launchpad.net/pyephem/announcements.atom">Atom/RSS
feed</a>.
You will still see the project mentioned here
whenever a technical or scientific issue
becomes interesting enough for me to write about;
but the audience of astronomers and hobbyists
who just need to know when the next version is released
should not have to wade through my blog to do so!
</p>

<p>
My users have already begun transferring
their questions and problems to Lauchpad,
and I look forward to offering much greater accountability
through a fully public development process.
</p>]]></content:encoded>
    </item>
    <item>
      <title>Wordle</title>
      <link>http://rhodesmill.org/brandon/2008/wordle/</link>
      <pubDate>Fri, 13 Jun 2008 00:35:29 EDT</pubDate>
      <category><![CDATA[web notes]]></category>
      <category><![CDATA[computing]]></category>
      <guid>http://rhodesmill.org/brandon/?p=18</guid>
      <description>Wordle</description>
      <content:encoded><![CDATA[
What fun! An application has been placed on the Web named <a href="http://www.wordle.net/">Wordle</a> which, given some paragraphs of text as input, produces very striking images by drawing the most important words from your document so that they are largest. The basic idea is a long-standing one on the Web, as exemplified in dozens of sites with <a href="http://www.flickr.com/photos/brandonrhodes/tags/">busy and ugly tag clouds</a> whose halfhearted attempt to create interest by varying their font size barely makes the idea worthwhile. But viewing Wordle, I am simply startled that word frequency analysis can produce something so beautiful! Here, as an example, someone has submitted the Constitution:

<a href="http://www.wordle.net/gallery/Constitution_of_the_United_States_of_America" title="Wordle: Constitution of the United States of America"><img src="http://www.wordle.net/thumb/Constitution_of_the_United_States_of_America" style="padding:4px;border:1px solid #ddd" alt="Constitution Wordle" />United States Constitution</a>

One can spend several minutes just staring at the words so basic to our national life, and pondering the significance of their relative sizes! To make my own contribution to the burgeoning world of Wordle documents, I created a program to extract the memorial messages from the <a href="http://www.legacy.com/PostGazette/GB/GuestbookView.aspx?PersonId=98788905">Marshall Booth Guest Book</a> on <tt>legacy.com</tt>, and then submitted the result to Wordle. After several tries, and after experimenting with the color options, I came up with something I find quite satisfactory:

<a href="http://www.wordle.net/gallery/Marshall_Booth_memorial" title="Wordle: Marshall Booth memorial"><img src="http://www.wordle.net/thumb/Marshall_Booth_memorial" style="padding:4px;border:1px solid #ddd" alt="Marhsall Booth Wordle" />Marshall Booth memorial</a>

I am sure that Wordle documents will look rather formulaic once everyone has used them to generate Christmas cards one or two years in a row. But they are without question of much greater visual interest than any other tag cloud I have ever seen, and are therefore a big step forward simply by making word frequency something worth staring at.

It would be fun to submit novels, or theological treatises, or each of the books of Paul, to Wordle and then see whether students of English literature or Biblical exegesis could identify the original document simply by which words appeared the most often. I think there would be interesting surprises! Could people tell apart the five acts of Hamlet?]]></content:encoded>
    </item>
    <item>
      <title>A database symbol for GraphViz</title>
      <link>http://rhodesmill.org/brandon/2007/a-database-symbol-for-graphviz/</link>
      <pubDate>Fri, 23 Nov 2007 10:12:37 EST</pubDate>
      <category><![CDATA[web notes]]></category>
      <category><![CDATA[computing]]></category>
      <guid>http://rhodesmill.org/brandon/2007/a-database-symbol-for-graphviz/</guid>
      <description>A database symbol for GraphViz</description>
      <content:encoded><![CDATA[
<blockquote>
<b>Download the source for my GraphViz database symbol featured in this article:</b> <a href="/brandon/static/2007-11/DatabaseShape.ps">DatabaseShape.ps</a>
</blockquote>

I have started using the <a href="http://www.graphviz.org/">GraphViz</a> application, which accepts a list of nodes and arrows, and figures out how to attractively arrange them in a diagram. For example, you can very nearly produce this output:

<img src="/brandon/static/2007-11/graphviz-with-database" />

by supplying this rather modest input file to GraphViz (most of whose length comes from my wanting particular colors)::


<div class="pygments_murphy syntax_highlight"><pre> <span class="n">digraph</span> <span class="n">Application</span> <span class="p">{</span><br/>    <span class="n">rankdir</span><span class="o">=</span><span class="n">LR</span><span class="p">;</span><br/>    <span class="n">node</span> <span class="p">[</span><span class="n">shape</span><span class="o">=</span><span class="n">box</span><span class="p">,</span><span class="n">style</span><span class="o">=</span><span class="n">filled</span><span class="p">,</span><span class="n">fillcolor</span><span class="o">=</span><span class="s">&quot;#C0D0C0&quot;</span><span class="p">];</span><br/>    <span class="n">subgraph</span> <span class="n">clusterClient</span> <span class="p">{</span><br/>       <span class="n">label</span><span class="o">=</span><span class="s">&quot;Client&quot;</span><span class="p">;</span> <span class="n">style</span><span class="o">=</span><span class="n">filled</span><span class="p">;</span> <span class="n">bgcolor</span><span class="o">=</span><span class="s">&quot;#D0C0A0&quot;</span><span class="p">;</span><br/>       <span class="s">&quot;Browser&quot;</span><span class="p">;</span><br/>    <span class="p">};</span><br/>    <span class="n">subgraph</span> <span class="n">clusterServer</span> <span class="p">{</span><br/>       <span class="n">label</span><span class="o">=</span><span class="s">&quot;Server&quot;</span><span class="p">;</span> <span class="n">style</span><span class="o">=</span><span class="n">filled</span><span class="p">;</span> <span class="n">bgcolor</span><span class="o">=</span><span class="s">&quot;#D0C0A0&quot;</span><span class="p">;</span><br/>       <span class="s">&quot;App&quot;</span><span class="p">;</span><br/>       <span class="s">&quot;Database&quot;</span> <span class="p">[</span><span class="n">shape</span><span class="o">=</span><span class="n">DatabaseShape</span><span class="p">,</span><span class="n">peripheries</span><span class="o">=</span><span class="mi">0</span><span class="p">];</span><br/>    <span class="p">};</span><br/>    <span class="s">&quot;Browser&quot;</span> <span class="o">-&gt;</span> <span class="s">&quot;App&quot;</span> <span class="p">[</span><span class="n">label</span><span class="o">=</span><span class="s">&quot;HTTP&quot;</span><span class="p">];</span><br/>    <span class="s">&quot;App&quot;</span> <span class="o">-&gt;</span> <span class="s">&quot;Database&quot;</span> <span class="p">[</span><span class="n">label</span><span class="o">=</span><span class="s">&quot;SQL&quot;</span><span class="p">];</span><br/> <span class="p">}</span><br/></pre></div>



I used the words “very nearly” because, in fact, GraphViz only knows how to draw simple shapes like rectangles, and is ignorant of the standard cylinder-shaped database symbol that I have used here by asking for a <tt>DatabaseShape</tt>. Submitting the above code to GraphViz will, normally, produce three nodes that are all rectangles. To teach it about the database shape, I had to write some PostScript.

<!--more-->

The PostScript language is a beautifully compact version of the venerable FORTH language, and operates more or less like a Hewlett-Packard reverse Polish notation calculator hooked up to a sleeker version of the turtle from Logo. A program typically places numbers on the stack, perhaps invokes some mathematical operators on them, and finally invokes a graphics operation which uses those numbers as coordinates. For example, consider this code:


<div class="pygments_murphy syntax_highlight"><pre><span class="n">x1</span> <span class="n">x0</span> <span class="n">sub</span> <span class="mi">2</span> <span class="n">div</span> <span class="n">y0</span> <span class="n">lineto</span><br/></pre></div>



This means, “place the value of the variable <i>x1</i> on the stack, then the value of <i>x0</i>, and then <i>subtract</i> to remove them from the stack and leave their difference there instead; then place the number <i>2</i> on the stack and <i>divide</i> so that only half of the previous result remains; then place the value of <i>y0</i> on the stack; and, finally, invoke the command <i>lineto</i> which removes the bottom two numbers from the stack and interprets them as the coordinates of a point to which it then draws a line.” In Python the same expression would be:


<div class="pygments_murphy syntax_highlight"><pre><span class="n">lineto</span><span class="p">((</span><span class="n">x1</span> <span class="o">-</span> <span class="n">x0</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="n">y0</span><span class="p">)</span><br/></pre></div>



Even small PostScript programs like my <a href="/brandon/static/2007-11/DatabaseShape.ps">DatabaseShape.ps</a> tend to wind up using a dozen or more different coordinates, so I always have to work first with pencil and paper to sketch the shape and define the variable names for my coordinates before then turning to my keyboard to write the code. It makes me remember my childhood, drawing things on graph paper before writing a BASIC program to draw the same shape on the screen.

One annoyance with using a user-defined shape like this with GraphViz is that one is restricted to using only its PostScript output mode, which means having to use an additional command to turn the PostScript into PDF or PNG or some other format. For example, if the example GraphViz code that I quoted above is placed in a <tt>sample.dot</tt> file, then to generate a PDF of the graph one must perform two steps:


<div class="pygments_murphy syntax_highlight"><pre><span class="nv">$ </span>dot -Tps2 -l DatabaseShape.ps sample.dot -o sample.ps<br/><span class="nv">$ </span>ps2pdf sample.ps sample.pdf<br/></pre></div>



But since all the system diagrams that I need to produce at work will need to have databases in them, I'm just happy that I've worked out how to display the shape at all.
]]></content:encoded>
    </item>
  </channel>
</rss>

