<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Tom Moertel's Weblog</title>
    <link>http://blog.moertel.com/</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Quality rants on programming theory and stuff geeks like</description>
    <item>
      <title>See you at the Pittsburgh Perl Workshop 2008!</title>
      <description>&lt;p&gt;The &lt;a href="http://pghpw.org/ppw2008/"&gt;2008 Pittsburgh Perl Workshop&lt;/a&gt; is this
weekend!  I can&amp;#8217;t wait. (BTW, there are still seats available.  If you
can somehow get yourself to Pittsburgh this weekend, by
all means, &lt;a href="http://pghpw.org/ppw2008/purchase"&gt;grab a &lt;span class="caps"&gt;PPW&lt;/span&gt;
ticket&lt;/a&gt; &lt;em&gt;now&lt;/em&gt;.)&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;m on the organizing committee, so I get an advance look at the
talks, and I&amp;#8217;m continually impressed by the quantity and sheer
interestingness of the things that the Perl community has to say.
When leading members of a community &lt;em&gt;volunteer&lt;/em&gt; their time to talk to
you about something they&amp;#8217;re passionate about, that something is
usually fascinating.&lt;/p&gt;


	&lt;p&gt;This year is no exception.  There are tons of talks I want to see.  Check out the schedule for
&lt;a href="http://pghpw.org/ppw2008/schedule?day=2008-10-11"&gt;Saturday&lt;/a&gt; and
&lt;a href="http://pghpw.org/ppw2008/schedule?day=2008-10-12"&gt;Sunday&lt;/a&gt;,
and you&amp;#8217;ll see what I mean.  (You&amp;#8217;ll note that there are even
talks on programming GPUs and adorable &lt;span class="caps"&gt;BUG&lt;/span&gt; embedded hardware.)&lt;/p&gt;


	&lt;p&gt;In addition to technical talks, there are &lt;em&gt;three&lt;/em&gt; courses being
offered this year.  Daniel Klein is once again leading his &lt;a href="http://pghpw.org/ppw2008/zerotoperl.html"&gt;From Zero
To Perl&lt;/a&gt; introductory course, which was widely praised at last year&amp;#8217;s
&lt;span class="caps"&gt;PPW&lt;/span&gt;.  Author and Perl trainer Peter Scott is offering &lt;a href="http://pghpw.org/ppw2008/maintainingcode.html"&gt;Maintaining
Code While Staying Sane&lt;/a&gt;, which is all about maintaining legacy code,
something most programmers must do for a (surprisingly) large chunk of
their careers.  Finally, the ever-knowledgeable brian d foy is
offering his &lt;a href="http://pghpw.org/ppw2008/masteringperl.html"&gt;Mastering Perl&lt;/a&gt; course for coders interested in learning
how to reliably write professional, enterprise-quality Perl programs.
(I think there are openings for some of the classes, too.  If you&amp;#8217;re interested,
click one of the links above and try to grab a spot.)&lt;/p&gt;


	&lt;p&gt;This year we&amp;#8217;re expanding on the Hackathons, too.  We actually have
allocated a dedicated &amp;#8220;Hackathon Room&amp;#8221; &amp;#8211; and we&amp;#8217;ve arranged for
freshly ground, freshly brewed coffee all day long to fuel the
hacking.  &lt;code&gt;:-)&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;All in all, it&amp;#8217;s shaping up to be another fun-filled, festive &lt;span class="caps"&gt;PPW&lt;/span&gt;.
I hope to see you there!&lt;/p&gt;</description>
      <pubDate>Wed, 08 Oct 2008 21:04:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:35955fc4-0c83-4e36-8e3c-74627f056f48</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/10/08/see-you-at-the-pittsburgh-perl-workshop-2008</link>
      <category>perl</category>
      <category>perl</category>
      <category>ppw</category>
      <category>ppw08</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/830</trackback:ping>
    </item>
    <item>
      <title>The Insecurity of Security Questions: Why I met my wife in CWmKryWzuxCSAnMDuIg.</title>
      <description>&lt;p&gt;Via &lt;a href="http://www.25hoursaday.com/weblog/2008/09/19/TheProblemWithEveryImplementationOfAForgotYourPasswordFeatureIveSeenOnline.aspx"&gt;Dare Obasanjo&amp;#8217;s blog&lt;/a&gt;, I learned
that the much-publicized cracking of Sarah Palin&amp;#8217;s Yahoo! email accounts was
accomplished by &lt;a href="http://blog.wired.com/27bstroke6/2008/09/palin-e-mail-ha.html"&gt;exploiting the weakness of &amp;#8220;security questions&amp;#8221;&lt;/a&gt;.  In short, all the attacker needed to do to convince Yahoo&amp;#8217;s computers that he was Palin was answer three questions as if he were Palin:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;What&amp;#8217;s your birthday?&lt;/li&gt;
		&lt;li&gt;What&amp;#8217;s your Zip code?&lt;/li&gt;
		&lt;li&gt;Where did you meet your spouse?&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;The attacker says he obtained the answers to these questions in less
than an hour. Everything he needed was already public knowledge, and
Google and Wikipedia made that knowledge easy to find.&lt;/p&gt;


	&lt;p&gt;And that&amp;#8217;s why when I sign up for web sites that ask me to provide baseline answers for those annoying security
questions, I claim that I met my spouse
in &lt;strong&gt;CWmKryWzuxCSAnMDuIg&lt;/strong&gt;.  What?  You&amp;#8217;ve never been there?  Well, that&amp;#8217;s not surprising.  It&amp;#8217;s not a real
place: it&amp;#8217;s a password, randomly generated, and remembered for me by
password-management software on my computer.&lt;/p&gt;


	&lt;p&gt;That&amp;#8217;s right.  Every time I&amp;#8217;m asked to establish my &amp;#8220;secret&amp;#8221; answer to a
security question, I generate a random string and use that.  Here&amp;#8217;s a
script I use:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;#!/usr/bin/perl

use MIME::Base64;

open my $random, "/dev/urandom" 
    or die "can't open /dev/urandom";
my $bytes;
read $random, $bytes, 16;
close $random;

my $pw = encode_base64($bytes);
$pw =~ tr/A-Za-z0-9//cd;
print "$pw$/";
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Then I store the string in my password-management software, just in
case the web site asks me for it later.  Which should only happen if I
forget my primary password for that site.  Which should only happen if
I can&amp;#8217;t get into my password-management software.  Which should only happen if I&amp;#8217;m totally screwed, anyway, so what are the security questions buying me again?&lt;/p&gt;


	&lt;p&gt;In sum, if you care about your security, you&amp;#8217;re probably picking good passwords already. In that case, security questions can&amp;#8217;t help you, but they can harm you by making it easier for an attacker bypass your passwords. That&amp;#8217;s how the Palin-email cracker did it. So treat your answers to security questions as if they were passwords &amp;#8211; in effect, that&amp;#8217;s what they are.&lt;/p&gt;</description>
      <pubDate>Fri, 19 Sep 2008 11:06:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:511abe62-31c3-4d20-bdb8-8cfb827b2c61</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/09/19/the-insecurity-of-security-questions-why-i-met-my-wife-in-cwmkrywzuxcsanmduig</link>
      <category>security</category>
      <category>security</category>
      <category>passwords</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/816</trackback:ping>
    </item>
    <item>
      <title>PXSL Tools now on Hackage and GitHub</title>
      <description>&lt;p&gt;I finally got around to releasing &lt;a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/package/pxsl-tools"&gt;&lt;span class="caps"&gt;PXSL&lt;/span&gt; Tools on Hackage&lt;/a&gt;.  The package contains &lt;em&gt;pxslcc&lt;/em&gt;, a preprocessor that converts &lt;a href="http://community.moertel.com/ss/space/PXSL"&gt;Parsimonious &lt;span class="caps"&gt;XML&lt;/span&gt; Shorthand Language&lt;/a&gt; into &lt;span class="caps"&gt;XML&lt;/span&gt;, and supporting documentation.&lt;/p&gt;


	&lt;p&gt;If you want to hack on the Haskell sources, I&amp;#8217;ve put the project on GitHub, too.  See the &lt;a href="https://github.com/tmoertel/pxsl-tools/tree"&gt;pxsl-tools project page&lt;/a&gt; to browse the code, or just clone the repo and hack away:&lt;/p&gt;


&lt;pre&gt;$ git clone git://github.com/tmoertel/pxsl-tools.git
&lt;/pre&gt;</description>
      <pubDate>Sun, 24 Aug 2008 22:56:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:888e0d81-d509-4041-a75b-ee91ce921b4d</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/08/24/pxsl-tools-now-on-hackage-and-github</link>
      <category>haskell</category>
      <category>git</category>
      <category>pxsl</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/808</trackback:ping>
    </item>
    <item>
      <title>Thinking algebraically: a functional-programming dividend that pays during your imperative-programming day job</title>
      <description>&lt;p&gt;Although at work I code mostly in Python &amp;#8211; a language from which
&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=98196"&gt;&lt;em&gt;lambda&lt;/em&gt; and &lt;em&gt;map&lt;/em&gt; were nearly removed&lt;/a&gt; &amp;#8211; I still find that functional-programming experience
has its benefits.  One of the
&amp;#8220;functional-programming dividends&amp;#8221; I notice most often is insight
gained from considering problems from an algebraic perspective.&lt;/p&gt;


	&lt;p&gt;Recently, for example, I had a small parsing problem.  I had to
write code that, given a simple grammar specification as input, emits
a regular expression that matches the language generated by the
grammar.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s a simplified version of the problem.  A grammar specification
is limited to a series of one or more &lt;em&gt;atoms&lt;/em&gt;.  For example, &amp;#8220;a b c&amp;#8221; 
represents the atom &amp;#8220;a&amp;#8221;, followed by the atom &amp;#8220;b&amp;#8221;, followed by the
atom &amp;#8220;c&amp;#8221;.  To generate the grammar, the series of atoms is interpreted
such that each atom (except the last) generates a production rule of
the following form:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;atom_rule ::=
  &amp;lt;the literal atom&amp;gt; (SPACE &amp;lt;the next rule&amp;gt; | NOTHING)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;(SPACE represents literal white space and &lt;span class="caps"&gt;NOTHING&lt;/span&gt; represents an
empty string.)  The grammar as a whole is rooted in the first atom&amp;#8217;s
rule.&lt;/p&gt;


	&lt;p&gt;Thus the specification &amp;#8220;a b c&amp;#8221; represents the following grammar:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;grammar ::= a_rule
a_rule  ::= "a" (SPACE b_rule | NOTHING)
b_rule  ::= "b" (SPACE c_rule | NOTHING)
c_rule  ::= "c" 
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Note that the final atom&amp;#8217;s production matches only the literal atom
itself: it has no following rule on which to chain.&lt;/p&gt;


	&lt;p&gt;The grammar, in turn, generates the following language:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;a
a b
a b c
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Thus, given the grammar specification &amp;#8220;a b c&amp;#8221;, my code had to produce
a regular expression that would match &amp;#8220;a&amp;#8221;, &amp;#8220;a b&amp;#8221;, or &amp;#8220;a b c&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;At this point, please stop for a moment and think about this little
programming exercise.  Do any solutions leap to mind?  How would you
approach the problem?  Form your opinions now, because I&amp;#8217;m going to
ask you about them later. (If you&amp;#8217;re feeling especially caffeinated, try
coding a solution before reading on.)&lt;/p&gt;&lt;p&gt;For me, the insight that made the exercise easy was seeing that the
grammar is given by folding a (suitably defined) right-associative
binary operator through the series of atoms.  The relationship might
be easier to see if you substitute away the intermediate production
rules from the grammar above:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;grammar ::= "a" (SPACE "b" (SPACE "c" | NOTHING) | NOTHING)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you squint past the &lt;span class="caps"&gt;SPACE&lt;/span&gt; and &lt;span class="caps"&gt;NOTHING&lt;/span&gt; terms, you&amp;#8217;ll see that the
grammar has the form&lt;/p&gt;


&lt;p&gt;(&lt;em&gt;a&lt;/em&gt; + (&lt;em&gt;b&lt;/em&gt; + (&lt;em&gt;c&lt;/em&gt;)))&lt;/p&gt;

	&lt;p&gt;The + is a binary operator that generates the parts we squinted away.
Once you see what&amp;#8217;s going on structurally, the operator is easy to
define:&lt;/p&gt;


&lt;p&gt;&lt;em&gt;x&lt;/em&gt; + &lt;em&gt;y&lt;/em&gt;  =  &lt;em&gt;x&lt;/em&gt; (SPACE &lt;em&gt;y&lt;/em&gt; | &lt;span class="caps"&gt;NOTHING&lt;/span&gt;)&lt;/p&gt;

&lt;p&gt;Compare the operator&amp;#8217;s definition with that of the
&lt;code&gt;atom_rule&lt;/code&gt; I presented at the beginning of the article.
They&amp;#8217;re structurally the same: the operator&amp;#8217;s &lt;em&gt;x&lt;/em&gt; and
&lt;em&gt;y&lt;/em&gt; are the atom rule&amp;#8217;s &lt;code&gt;&amp;lt;the literal atom&amp;gt;&lt;/code&gt; and
&lt;code&gt;&amp;lt;the next rule&amp;gt;&lt;/code&gt;.&lt;/p&gt;

	&lt;p&gt;Now all that remains is to generalize the &amp;#8220;a b c&amp;#8221; formula into a
general formula that works for arbitrary grammar specifications.
Fortunately, this work has already been done for us.  The generalized
formula is nothing more than a &lt;a href="http://www.haskell.org/haskellwiki/Fold"&gt;right fold&lt;/a&gt;.  In Haskell, the
particular right-fold flavor we want is called &lt;em&gt;foldr1&lt;/em&gt;.&lt;/p&gt;


	&lt;p&gt;Given a list of atoms, we can use &lt;em&gt;foldr1&lt;/em&gt; to construct its grammar as
follows:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;mk_grammar atoms = foldr1 (+) atoms
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;But Python, our implementation language, does not offer a &lt;em&gt;foldr1&lt;/em&gt;
function.  This wrinkle, however, is another thing we can iron out by
thinking algebraically.  Python doesn&amp;#8217;t have &lt;em&gt;foldr1&lt;/em&gt;, but it does
have a &lt;em&gt;reduce&lt;/em&gt; function, which represents a left fold, equivalent to
Haskell&amp;#8217;s &lt;em&gt;foldl&amp;#8217;&lt;/em&gt; or &lt;em&gt;foldl1&amp;#8217;&lt;/em&gt;.  Because our + operator is strict and
our list of atoms is finite, we can take advantage of the following
identity:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;foldr1 (+) xs == foldl1 (flip (+)) (reverse xs)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;That is, we can convert a right fold into a left fold by flipping the
arguments of the operator and operating on the list in reverse.  Thus
we can implement the fold we &lt;em&gt;want&lt;/em&gt; in terms of the fold we &lt;em&gt;have&lt;/em&gt;:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;# Python code

def foldr1(f, xs):
    return reduce(flip(f), reversed(xs))

def flip(f):
    def g(x, y):
        return f(y, x)
    return g
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now writing a Python-based solution is straightforward:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;def grammar_spec_to_re(spec):
    atoms = grammar_spec_to_atoms(spec)
    atom_res = map(atom_to_re, atoms)
    grammar_re = r'\A%s\Z' % foldr1(op, atom_res)
    return grammar_re

def op(x, y):
    # x + y = x (SPACE y | NOTHING)
    return r'%s(\s+%s)?' % (x, y)

def grammar_spec_to_atoms(spec):
    return spec.split()

def atom_to_re(atom):
    return re.escape(atom)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Using our solution, let&amp;#8217;s compile the &amp;#8220;a b c&amp;#8221; grammar specification
into its corresponding regular expression:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print grammar_spec_to_re('a b c')
\Aa(\s+b(\s+c)?)?\Z
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And that&amp;#8217;s basically how I solved the problem.&lt;/p&gt;


	&lt;p&gt;To play around with the solution, here&amp;#8217;s a small helper class that compiles a grammar specification into a regular expression and then tests strings for matching the regexp:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;class GrammarMatcher(object):
    def __init__(self, spec):
        self.re = re.compile(grammar_spec_to_re(spec))
    def __call__(self, s):
        return not not self.re.match(s)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now, let&amp;#8217;s try out the regular expression generated for the grammar specification &amp;#8220;a b c&amp;#8221; :&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; matcher = GrammarMatcher('a b c')
&amp;gt;&amp;gt;&amp;gt; matcher('')
False
&amp;gt;&amp;gt;&amp;gt; matcher('a')
True
&amp;gt;&amp;gt;&amp;gt; matcher('ab')
False
&amp;gt;&amp;gt;&amp;gt; matcher('a b')
True
&amp;gt;&amp;gt;&amp;gt; matcher('a  b')
True
&amp;gt;&amp;gt;&amp;gt; matcher('a b c')
True
&amp;gt;&amp;gt;&amp;gt; matcher('a b c d')
False
&amp;gt;&amp;gt;&amp;gt; matcher('a c')
False
&amp;gt;&amp;gt;&amp;gt; matcher('b')
False
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now, those questions I promised.  If you&amp;#8217;re a functional programmer,
did a fold-based solution leap out at you?  (Did you think of the
&lt;em&gt;problem&lt;/em&gt; in terms of folds?)  If you&amp;#8217;re not a functional programmer,
how did you see the problem?  Did the solution above seem twisted,
confusing, or overly clever?&lt;/p&gt;


	&lt;p&gt;(There are no right or wrong answers.  I&amp;#8217;m just curious about how
people with different backgrounds view the problem.)&lt;/p&gt;


&lt;div class="update"&gt;
&lt;strong&gt;Update:&lt;/strong&gt; Edited to clarify that the problem is to convert a grammar specification into a regular expression, not just test whether a string matches a specified grammar.
&lt;/div&gt;</description>
      <pubDate>Wed, 20 Aug 2008 21:50:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:a80d7a49-0278-48b0-badb-ffe38a216762</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/08/20/thinking-algebraically-a-functional-programming-dividend-that-pays-during-your-imperative-programming-day-job</link>
      <category>functional programming</category>
      <category>haskell</category>
      <category>fp</category>
      <category>python</category>
      <category>folds</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/766</trackback:ping>
    </item>
    <item>
      <title>Fun stuff: Video of Type B Erie steam shovel in action!</title>
      <description>&lt;p&gt;As an update to my &lt;a href="http://blog.moertel.com/articles/2008/08/09/fun-stuff-historical-construction-equipment-associations-2008-convention"&gt;previous post on the 2008 convention of the Historical Construction Equipment Association&lt;/a&gt;, I have posted an action-packed video of a Type-B Erie steam-powered shovel! Wait until you see this old beast belch steam and smoke and you hear it &lt;em&gt;chug, clank,&lt;/em&gt; and &lt;em&gt;huff and puff&lt;/em&gt; &amp;#8211; it&amp;#8217;s like stepping back in time. And it&amp;#8217;s definately &lt;em&gt;fun stuff&lt;/em&gt;!&lt;/p&gt;


&lt;div class="slide"&gt;
&lt;a href="http://www.flickr.com/photos/tmoertel/2750568956/"&gt;&lt;img src="http://farm4.static.flickr.com/3094/2750568956_9da340eddb_m.jpg" alt="" /&gt;&lt;/a&gt;
&lt;/div&gt;

	&lt;p&gt;I took this footage on 8 August 2008 in Brownsville, Pennsylvania. (I also have footage of other equipment &amp;#8211; dozers, draglines, trucks, shovels, and more. Let me know if you&amp;#8217;re interested, and I&amp;#8217;ll upload those, too.)&lt;/p&gt;


&lt;div class="update"&gt;
&lt;strong&gt;Update:&lt;/strong&gt; I have uploaded the rest of my footage to flickr:

	&lt;ul&gt;
	&lt;li&gt;Thew &amp;#8220;O&amp;#8221; steam shovel&lt;/li&gt;
		&lt;li&gt;Dragline&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;CAT 955&lt;/span&gt; bulldozer&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;CAT D8&lt;/span&gt; bulldozer&lt;/li&gt;
		&lt;li&gt;Vintage Army dump truck&lt;/li&gt;
	&lt;/ul&gt;


See them all in &lt;a href="http://flickr.com/photos/tmoertel/sets/72157606638346521/"&gt;my &lt;span class="caps"&gt;HCEA 2008&lt;/span&gt; photostream&lt;/a&gt;.
&lt;/div&gt;</description>
      <pubDate>Sun, 10 Aug 2008 14:12:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:fc0aa415-ec6c-44aa-9e5b-86150afd55f1</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/08/10/fun-stuff-video-of-type-b-erie-steam-shovel-in-action</link>
      <category>fun stuff</category>
      <category>hcea</category>
      <category>hcea2008</category>
      <category>fun_stuff</category>
      <category>video</category>
      <category>steam_shovel</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/760</trackback:ping>
    </item>
    <item>
      <title>Fun stuff: Historical Construction Equipment Association's 2008 convention</title>
      <description>&lt;p&gt;Today, my dad and I went to the 2008 annual convention of the &lt;a href="http://www.hcea.net/"&gt;Historical Construction Equipment Association&lt;/a&gt;.  We were impressed with the quantity and quality of the machinery on &lt;em&gt;active&lt;/em&gt; display: steam shovels, dozers, graders, crawlers, scrapers, cranes, steamrollers, and a bunch of other old but well-maintained construction equipment. I&amp;#8217;m talking dozens of massive machines &amp;#8211; not just sitting there, but &lt;em&gt;working&lt;/em&gt;!&lt;/p&gt;


	&lt;p&gt;This year&amp;#8217;s convention is in Brownsville, Pennsylvania and runs through August 10, 2008. If you are within driving distance and think smoke-belching, earth-shaking construction equipment is fun stuff, don&amp;#8217;t miss it. There&amp;#8217;s still time to go.&lt;/p&gt;


	&lt;p&gt;If you can&amp;#8217;t make it, &lt;a href="http://flickr.com/photos/tmoertel/sets/72157606638346521/"&gt;I took some photos for you&lt;/a&gt;. Not quite the real thing, but better than nothing.&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://community.moertel.com/~thor/pix/blog-20080809/hcea2008-steam-shovel.jpg" alt="" /&gt;&lt;/p&gt;


&lt;div class="update"&gt;
&lt;strong&gt;Update:&lt;/strong&gt; I have posted a &lt;a href="http://blog.moertel.com/articles/2008/08/10/fun-stuff-video-of-type-b-erie-steam-shovel-in-action"&gt;video of a Type B Erie steam shovel&lt;/a&gt; &amp;#8211; the one pictured above &amp;#8211; and it&amp;#8217;s &lt;em&gt;in action&lt;/em&gt;! Don&amp;#8217;t miss it.
&lt;/div&gt;</description>
      <pubDate>Sat, 09 Aug 2008 20:23:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:48dfe866-fb16-480d-b502-4425c1874c9b</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/08/09/fun-stuff-historical-construction-equipment-associations-2008-convention</link>
      <category>fun stuff</category>
      <category>hcea</category>
      <category>hcea2008</category>
      <category>fun_stuff</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/759</trackback:ping>
    </item>
    <item>
      <title>Oleg's great way of explaining delimited continuations</title>
      <description>&lt;p&gt;There&amp;#8217;s a great way to explain delimited continuations in the notes of &lt;a href="http://okmij.org/ftp/Computation/Continuations.html#shift-cgi"&gt;Oleg&amp;#8217;s Continuation Fest talk on using delimited continuations for &lt;span class="caps"&gt;CGI&lt;/span&gt; programming&lt;/a&gt;.  Just so it doesn&amp;#8217;t get overlooked, here it is:&lt;/p&gt;


&lt;blockquote&gt;I&amp;#8217;m obsessed in pointing out that every programmer already knows
and understands the delimited continuations; they might not know that
word though.  Everyone knows that when a process executes a system
call like &lt;code&gt;read&lt;/code&gt;, it gets &lt;em&gt;suspended&lt;/em&gt;. When the disk
delivers the data, the process is &lt;em&gt;resumed&lt;/em&gt;. That suspension of a
process is its continuation. It is delimited: it is not the
check-point of the whole OS, it is the check-point of a process only,
from the invocation of &lt;code&gt;main()&lt;/code&gt; up to the point
&lt;code&gt;main()&lt;/code&gt; returns. Normally these suspensions are resumed
only once, but can be zero times (&lt;code&gt;exit&lt;/code&gt;) or twice
(&lt;code&gt;fork&lt;/code&gt;).&lt;/blockquote&gt;

&lt;p&gt;I especially like the final part about &lt;code&gt;exit&lt;/code&gt; and
&lt;code&gt;fork&lt;/code&gt;, which drives home the notion that something more
subtle than returning from a typical function call is going on. If
anybody is confused over what &lt;em&gt;suspended&lt;/em&gt; means, that last part
ought to clear things up.&lt;/p&gt;

&lt;p&gt;The next time I need to explain delimited continuations, I know how
I&amp;#8217;m going to do it.&lt;/p&gt;</description>
      <pubDate>Mon, 05 May 2008 09:58:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:9030a189-530b-48b3-b5e1-ed41ab5c2467</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/05/05/olegs-great-way-of-explaining-delimited-continuations</link>
      <category>functional programming</category>
      <category>continuations</category>
      <category>fp</category>
      <category>oleg</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/724</trackback:ping>
    </item>
    <item>
      <title>That looks about right</title>
      <description>&lt;p&gt;Via &lt;a href="http://www.cwinters.com/news/display/3624"&gt;Chris&lt;/a&gt;:&lt;/p&gt;


&lt;pre&gt;$ history | awk '{print $2}' | sort | uniq -c | sort -rn | head
    196 git
    110 l
    102 cd
     70 make
     34 darcs
     30 pushd
     23 ssh
     23 m
     23 ls
     20 rm
&lt;/pre&gt;

	&lt;p&gt;The &lt;em&gt;l&lt;/em&gt; and &lt;em&gt;m&lt;/em&gt; commands are aliases:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;em&gt;l&lt;/em&gt; = &lt;em&gt;ls &amp;#8211;CF&lt;/em&gt;&lt;/li&gt;
		&lt;li&gt;&lt;em&gt;m&lt;/em&gt; = &lt;em&gt;less&lt;/em&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Fri, 11 Apr 2008 11:58:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:8c556b83-dcaa-4044-9f0f-7af434f6f3f7</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/04/11/that-looks-about-right</link>
      <category>interesting stuff</category>
      <category>programming</category>
      <category>life</category>
      <category>memes</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/715</trackback:ping>
    </item>
    <item>
      <title>Property checking with Python's nose testing framework</title>
      <description>&lt;p&gt;At work recently I was writing some tests with Python&amp;#8217;s out-of-the-box
unit-testing framework
&lt;a href="http://docs.python.org/lib/module-unittest.html"&gt;unittest&lt;/a&gt;.  I&amp;#8217;m new
to Python and accustomed to Perl and Haskell&amp;#8217;s testing frameworks,
which are lightweight and let you write tests without much
hoop-jumping.  In particular,
&lt;a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/"&gt;QuickCheck&lt;/a&gt; and
&lt;a href="http://search.cpan.org/dist/Test-LectroTest/"&gt;LectroTest&lt;/a&gt; make it easy
to test at the property level instead of the test-case level.
With unittest, I was having to write a lot of code
to get the same level of abstraction.&lt;/p&gt;


	&lt;p&gt;By &amp;#8220;property level,&amp;#8221; here&amp;#8217;s what I mean.  Say I&amp;#8217;m testing this thing,
let&amp;#8217;s call it a &lt;em&gt;subscriber pool&lt;/em&gt;.  It has two fundamental properties:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;Subscribe.&lt;/strong&gt; For all initial states of the pool, if you call &lt;em&gt;subscribe&lt;/em&gt;(&lt;em&gt;user&lt;/em&gt;), then, assuming there have been no other operations on the pool, &lt;em&gt;user&lt;/em&gt; must be in the pool.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Unsubscribe.&lt;/strong&gt; For all initial states of the pool, if you call &lt;em&gt;unsubscribe&lt;/em&gt;(&lt;em&gt;user&lt;/em&gt;), then, assuming there have been no other operations on the pool, &lt;em&gt;user&lt;/em&gt; must not be in the pool.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;That&amp;#8217;s it.  If my implementation satisfies both properties, it&amp;#8217;s
correct.  (This is a simplified version of my real testing problem,
which required additional property checks.)&lt;/p&gt;


	&lt;p&gt;To test whether my implementation satisfies each property, I must
write individual test cases that together &amp;#8220;cover&amp;#8221; the property.  For
example, to test whether the Subscribe property holds, I might write
four test cases:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;class SubscribeProperty(unittest.TestCase):

    def setUp(self):
        initialize_pool()

    def tearDown(self):
        destroy_pool()

    def testEmpty(self):
        load_pool_with_members([])
        subscribe("1")
        self.assert_("1" in pool_members())

    def testOtherGuyAlreadyInPool(self):
        load_pool_with_members(["2"])
        subscribe("1")
        self.assert_("1" in pool_members())

    def testSubscriberAlreadyInPool(self):
        load_pool_with_members(["1"])
        subscribe("1")
        self.assert_("1" in pool_members())

    def testSubscriberAndOtherGuyAlreadyInPool(self):
        load_pool_with_members(["1", "2"])
        subscribe("1")
        self.assert_("1" in pool_members())
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Every one of the test cases has the same form.  The repetition
makes me want to refactor the whole thing.&lt;/p&gt;


	&lt;p&gt;Okay, let&amp;#8217;s do it:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;INITIAL_POOL_STATES = [[], ["2"], ["1"], ["1", "2"]]

class SubscribeProperty(unittest.TestCase):

    def setUp(self):
        initialize_pool()

    def tearDown(self):
        destroy_pool()

    def testSubscribe(self):
        for case in INITIAL_POOL_STATES:
            self.setUp()
            try:
                load_pool_with_members(case)
                subscribe("1")
                self.assert_("1" in pool_members(), case)
            finally:
                self.tearDown()
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We&amp;#8217;re fighting a bit with the testing framework because our notion of
when set-up and tear-down should occur doesn&amp;#8217;t match its own, but
otherwise our code is looking much more manageable.  In particular, if
we want to extend our property-check coverage with additional initial pool
states, we don&amp;#8217;t need to write additional tests; instead, we can just
extend a single list.&lt;/p&gt;


	&lt;p&gt;But we&amp;#8217;re only halfway done.  We must also check the Unsubscribe
property.  The code for it is virtually the same as for Subscribe, but
with &lt;em&gt;subscribe&lt;/em&gt; becoming &lt;em&gt;unsubscribe&lt;/em&gt; and &lt;em&gt;in&lt;/em&gt; becoming &lt;em&gt;not in&lt;/em&gt;.
Let&amp;#8217;s add it to our class:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;class SubscriberPoolProperties(unittest.TestCase):

    def setUp(self):
        initialize_pool()

    def tearDown(self):
        destroy_pool()

    def testSubscribe(self):
        for case in INITIAL_POOL_STATES:
            self.setUp()
            try:
                load_pool_with_members(case)
                subscribe("1")
                self.assert_("1" in pool_members(), case)
            finally:
                self.tearDown()

    def testUnsubscribe(self):
        for case in INITIAL_POOL_STATES:
            self.setUp()
            try:
                load_pool_with_members(case)
                unsubscribe("1")
                self.assert_("1" not in pool_members(), case)
            finally:
                self.tearDown()
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And now let&amp;#8217;s factor out the new redundancy:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;class SubscriberPoolProperties(unittest.TestCase):

    def setUp(self):
        initialize_pool()

    def tearDown(self):
        destroy_pool()

    def testSubscribe(self):
        def testfn(case):
            subscribe("1")
            self.assert_("1" in pool_members(), case)
        self._forall_test_cases(testfn)

    def testUnsubscribe(self):
        def testfn(case):
            unsubscribe("1")
            self.assert_("1" not in pool_members(), case)
        self._forall_test_cases(testfn)

    def _forall_test_cases(self, testfn):
        for case in INITIAL_POOL_STATES:
            self.setUp()
            try:
                load_pool_with_members(case)
                testfn(case)
            finally:
                self.tearDown()
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;It&amp;#8217;s not bad, but it&amp;#8217;s not great either.  There&amp;#8217;s still a
lot of noise in that code.&lt;/p&gt;


	&lt;p&gt;After discussing the situation with my more-Pythonic
colleague &lt;a href="http://apipes.blogspot.com/"&gt;Tim Lesher&lt;/a&gt;, I took his
advice to check out the &lt;a href="http://somethingaboutorange.com/mrl/projects/nose/"&gt;nose testing framework&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;One of the things I liked right away about nose was that it supports
&lt;a href="http://somethingaboutorange.com/mrl/projects/nose/#test-generators"&gt;test
generators&lt;/a&gt;,
which would let me represent each property-check as a generator that
yields the test cases needed to check the property.  Also, set-up and
tear-down would automatically occur per &lt;em&gt;generated&lt;/em&gt; test, so I
wouldn&amp;#8217;t have to invoke them manually.&lt;/p&gt;


	&lt;p&gt;Once I got familiar with nose, it was easy to create a decorator to
represent the forall-test-cases idiom:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;def forall_cases(cases):
    def decorate(testfn):
        def gen():
            for case in cases:
                yield testfn, case
        gen.__name__ = "test_%s_for_a_case" % testfn.__name__
        return gen
    return decorate
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Note that this decorator is not specific to our subscriber-pool tests.
It can be used in any situation where we need to check a property
across a collection of cases.  In fact, I keep this little gem in a
&amp;#8220;nosehelpers&amp;#8221; library, where I reuse it all the time.  Here&amp;#8217;s an
example of how to use it to check the trivial property that
&lt;em&gt;x&lt;/em&gt;&amp;#160;=&amp;#160;&lt;em&gt;x&lt;/em&gt; for all &lt;em&gt;x&lt;/em&gt; in 0&amp;#8211;99:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;@forall_cases(range(100))
def check_self_equality(x):
    assert x == x
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now, back to our testing problem.  Here&amp;#8217;s how we can use the
decorator to check the Subscribe property:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;@forall_cases(INITIAL_POOL_STATES)
@with_setup(initialize_pool, destroy_pool)
def check_subscribe(case):
    load_pool_with_members(case)
    subscribe("1")
    assert "1" in pool_members()
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;(The &lt;em&gt;with_setup&lt;/em&gt; decorator is defined by nose and tells nose to run
the given set-up and tear-down functions before and after each of the
generated test cases.)&lt;/p&gt;


	&lt;p&gt;Not bad.  The only problem I have with that code is that it mixes the
&amp;#8220;For all initial states of the pool&amp;#8221; part of the property definition
into the &amp;#8220;if you call &lt;em&gt;subscribe&lt;/em&gt;(&lt;em&gt;user&lt;/em&gt;), then &amp;#8230;&amp;#8221; part.  I&amp;#8217;d like
the code to be more explicit about which part defines the scope of the
property claim and which part defines the test for whether the claim
holds for any particular test case within that scope.&lt;/p&gt;


	&lt;p&gt;Fortunately, we can build upon our existing decorator to create
exactly what we need:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;def forall_initial_pools(testfn):
    @forall_cases(INITIAL_POOL_STATES)
    @with_setup(initialize_pool, destroy_pool)
    def setup_case_and_test_it(case):
        load_pool_with_members(case)
        testfn(case)
    setup_case_and_test_it.__name__ = \
        "test_%s_for_a_subscriber_case" % testfn.__name__
    return setup_case_and_test_it
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Here&amp;#8217;s what the decorator does.  When you apply it to a test function
&lt;em&gt;testfn&lt;/em&gt;, it returns a test generator that yields a property-check
test for each of the initial pool states.  For each, it sets up a new
pool, loads it with the initial subscribers (as given by the
corresponding test case), runs the given check function &lt;em&gt;testfn&lt;/em&gt;, and
then cleans up after itself.&lt;/p&gt;


	&lt;p&gt;With this decorator, our Pythonic property definitions now mirror
the human-language definitions from the start of the article:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;@forall_initial_pools
def check_subscribe(case):
    subscribe("1")
    assert "1" in pool_members()

@forall_initial_pools
def check_unsubscribe(case):
    unsubscribe("1")
    assert "1" not in pool_members()
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And that&amp;#8217;s pretty much the solution I ended up using at work.  There,
as opposed to here, I got to reuse my decorators for many more tests,
making them all the more worth their small implementation price.&lt;/p&gt;</description>
      <pubDate>Wed, 19 Mar 2008 22:34:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:48416d65-7ef2-4453-9adc-6ee13f8e85b3</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2008/03/19/property-checking-with-pythons-nose-testing-framework</link>
      <category>testing</category>
      <category>testing</category>
      <category>python</category>
      <category>nose</category>
      <category>unittest</category>
      <category>properties</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/707</trackback:ping>
    </item>
    <item>
      <title>PXSL Tools 1.0: Your ticket out of XML Hell</title>
      <description>&lt;p&gt;&lt;span class="caps"&gt;XML&lt;/span&gt; is fine for representing document-like things, but when it&amp;#8217;s
twisted to represent build recipes, configuration files, and little
programming languages, it opens the gates to &lt;em&gt;&lt;span class="caps"&gt;XML&lt;/span&gt; Hell&lt;/em&gt;.  Once the
gates are opened, the demons of cargo-cult thinking are loosed upon
the world, where they are free to trick innocent programmers into
working with grotesquely twisted &lt;span class="caps"&gt;XML&lt;/span&gt; documents &amp;#8211; something no human
mind was designed to comprehend.  Ensnared, these programmers are
slowly drawn into the depths of &lt;span class="caps"&gt;XML&lt;/span&gt; Hell, from which their
&lt;a href="http://www.google.com/search?q=%22xml+hell%22"&gt;lamentations echo across the
universe&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;When the demons of cargo-cult thinking come for you, don&amp;#8217;t be
ensnared!  Instead, be prepared &amp;#8211; with &lt;span class="caps"&gt;PXSL&lt;/span&gt; &amp;#8211; the &lt;a href="http://community.moertel.com/ss/space/pxsl"&gt;Parsimonious &lt;span class="caps"&gt;XML&lt;/span&gt;
Shorthand Language&lt;/a&gt;
(pronounced &amp;#8220;pixel&amp;#8221;).&lt;/p&gt;


	&lt;p&gt;What&amp;#8217;s &lt;span class="caps"&gt;PXSL&lt;/span&gt;?  It&amp;#8217;s a luxurious, thermonuclear smoking jacket that you
can slip on using a convenient preprocessor.  Use it whenever you see
grotesque &lt;span class="caps"&gt;XML&lt;/span&gt; on the horizon.  Within &lt;span class="caps"&gt;PXSL&lt;/span&gt;&amp;#8217;s plush (and stylish)
protection, you can create all the nasty, twisted &lt;span class="caps"&gt;XML&lt;/span&gt; that may be
demanded of you, but you need not descend into &lt;span class="caps"&gt;XML&lt;/span&gt; Hell to do it.
Instead, you can work from the comfort of a well-stocked lounge, where
clarity and conciseness are always on tap.&lt;/p&gt;


	&lt;p&gt;For example, here&amp;#8217;s a snippet from an &lt;span class="caps"&gt;XSLT&lt;/span&gt; stylesheet, in the
original &lt;span class="caps"&gt;XML&lt;/span&gt;:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;&amp;lt;xsl:template match="/"&amp;gt;
  &amp;lt;xsl:for-each select="//*/@src|//*/@href"&amp;gt;
    &amp;lt;xsl:value-of select="."/&amp;gt;
    &amp;lt;xsl:text&amp;gt;&amp;amp;#10;&amp;lt;/xsl:text&amp;gt;
  &amp;lt;/xsl:for-each&amp;gt;
&amp;lt;/xsl:template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And here&amp;#8217;s the same snippet, written in &lt;span class="caps"&gt;PXSL&lt;/span&gt;:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;template /
  for-each //*/@src|//*/@href
    value-of .
    text &amp;lt;&amp;lt;&amp;amp;#10;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Isn&amp;#8217;t that refreshing?&lt;/p&gt;


	&lt;h3&gt;Why &lt;span class="caps"&gt;PXSL&lt;/span&gt;?&lt;/h3&gt;


	&lt;p&gt;There are lots of &lt;span class="caps"&gt;XML&lt;/span&gt; shorthands available.  (The &lt;a href="http://community.moertel.com/ss/space/PXSL/FAQs"&gt;&lt;span class="caps"&gt;PXSL FAQ&lt;/span&gt;&lt;/a&gt; lists about ten of them.)  So why choose
&lt;span class="caps"&gt;PXSL&lt;/span&gt;?  Here&amp;#8217;s why:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;PXSL&lt;/span&gt; lets you intermix &lt;span class="caps"&gt;PXSL&lt;/span&gt; and &lt;span class="caps"&gt;XML&lt;/span&gt; syntax&lt;/strong&gt; in one document. Feel free to use whichever syntax works best for each portion of your documents.  (See &lt;a href="http://community.moertel.com/pxsl/#xml-quoting-lt-lt-gt-gt-delimiters"&gt;the &lt;span class="caps"&gt;PXSL&lt;/span&gt; documentation&lt;/a&gt; for some examples.)&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;PXSL&lt;/span&gt; is customizable&lt;/strong&gt; with application-specific shortcuts.  (The &lt;span class="caps"&gt;PXSL&lt;/span&gt; snippet above, for example, uses &lt;span class="caps"&gt;XSLT&lt;/span&gt; shortcuts. Again, &lt;a href="http://community.moertel.com/pxsl/#element-defaults-provide-convenient-customizable-shortcuts"&gt;the &lt;span class="caps"&gt;PXSL&lt;/span&gt; documentation&lt;/a&gt; has examples.)&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;PXSL&lt;/span&gt; has a powerful macro system&lt;/strong&gt; that lets you build complicated document structures safely and conveniently.  (Read about &lt;a href="http://community.moertel.com/pxsl/#macro-facility"&gt;macros in the &lt;span class="caps"&gt;PXSL&lt;/span&gt; documentation&lt;/a&gt;.  For an advanced example of what you can do with &lt;span class="caps"&gt;PXSL&lt;/span&gt; macros, see this &lt;a href="http://www.kuro5hin.org/story/2003/6/4/12434/75716"&gt;article on refactoring &lt;span class="caps"&gt;XSLT&lt;/span&gt; one-offs into clean, maintainable code&lt;/a&gt;.)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Also, &lt;span class="caps"&gt;PXSL&lt;/span&gt; is battle tested.  It was first released in 2003 and has
been saving people from &lt;span class="caps"&gt;XML&lt;/span&gt; Hell since.  People who try it seem to like it:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;em&gt;I think &lt;span class="caps"&gt;PXSL&lt;/span&gt; could do wonders for soothing my irrational hatred for all things &lt;span class="caps"&gt;XML&lt;/span&gt;.&lt;/em&gt; &amp;#8212;&lt;a href="http://koweynlg.blogspot.com/2006/03/mmax-encore-encore-yay-pxsl.html"&gt;kowey&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;em&gt;Impressive&amp;#8230; I converted some of my files from &lt;span class="caps"&gt;XML&lt;/span&gt; to &lt;span class="caps"&gt;PXSL&lt;/span&gt; and the readability was much improved.&lt;/em&gt; &amp;#8212;&lt;a href="http://community.moertel.com/ss/comments/PXSL+Ask-a-Question#comment-PXSL%20Ask-a-Question-6"&gt;chris&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;em&gt;Quite aside from the fact that &lt;span class="caps"&gt;XSLT&lt;/span&gt; is finally somewhat readable, the fact that you&amp;#8217;ve added a serious macro system means that some serious scripting of &lt;span class="caps"&gt;XML&lt;/span&gt; can occur. I&amp;#8217;m very impressed.&lt;/em&gt; &amp;#8212;&lt;a href="http://community.moertel.com/ss/comments/PXSL+Ask-a-Question#comment-PXSL%20Ask-a-Question-4"&gt;invisible&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;The next time you&amp;#8217;re headed for &lt;span class="caps"&gt;XML&lt;/span&gt; Hell, why not &lt;a href="http://community.moertel.com/pxsl/#getting-or-building-the-pxsl-tools"&gt;give the venerable &lt;span class="caps"&gt;PXSL&lt;/span&gt; a try&lt;/a&gt;?  You might just find that you like it, too.&lt;/p&gt;


&lt;hr/&gt;

	&lt;p&gt;This public service announcement was brought to you in celebration of
the 1.0 release of the &lt;strong&gt;pxsl-tools&lt;/strong&gt; package.  The &lt;span class="caps"&gt;PXSL&lt;/span&gt;-to-XML compiler
&lt;em&gt;pxslcc&lt;/em&gt; is written in &lt;a href="http://haskell.org/"&gt;Haskell&lt;/a&gt; and uses the
cross-platform &lt;a href="http://www.haskell.org/cabal/"&gt;Haskell Cabal&lt;/a&gt;
build/package system to let you use &lt;span class="caps"&gt;PXSL&lt;/span&gt; just about anywhere.&lt;/p&gt;</description>
      <pubDate>Mon, 17 Dec 2007 22:33:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:fd34e396-beca-406a-9f9e-46a1dd5fe7ce</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2007/12/17/pxsl-tools-1-0-your-ticket-out-of-xml-hell</link>
      <category>programming</category>
      <category>haskell</category>
      <category>xml</category>
      <category>pxsl</category>
      <category>xslt</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/672</trackback:ping>
    </item>
  </channel>
</rss>
