<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>platypope.org / blog / syndicate</title>
  <link href="http://platypope.org/blog/syndicate" rel="self"/>
  <link href="http://platypope.org/blog/" rel="alternate"/>
  <id>http://platypope.org/blog/</id>
  <updated>2010-02-04T13:52:15-05:00</updated>
  <author>
    <name>Marshall T. Vandegrift</name>
  </author>
  <entry>
    <title>Confuse the customer... and win?</title>
    <link href="http://platypope.org/blog/2010/2/4/confuse-the-customer-and-win" rel="alternate"/>
    <id>urn:uuid:69a91540-11be-11df-a749-aa008bfedbfd</id>
    <updated>2010-02-04T13:52:15-05:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;With &lt;a href="http://whatever.scalzi.com/2010/02/01/all-the-many-ways-amazon-so-very-failed-the-weekend/"&gt;Amazon.com not selling Macmillian books&lt;/a&gt; at the moment, now might seem like
a good time to go to the source and &lt;a href="http://www.panmacmillan.com/Categories/EBooks/?SideNav=CategoryNav&amp;amp;SubjectID=55&amp;amp;Imprint="&gt;buy ebooks directly from Macmillian&lt;/a&gt;.  And
they even have multiple formats available!: the &amp;quot;Adobe Digital Edition&amp;quot; format
&lt;em&gt;and&lt;/em&gt; the &amp;quot;Adobe eReader&amp;quot; format.&lt;/p&gt;

&lt;p&gt;Wait, what?&lt;/p&gt;

&lt;p&gt;According to their &lt;a href="http://www.panmacmillan.com/Categories/Ebooks/displayPage.asp?PageTitle=Ebooks%20information%20and%20help"&gt;Ebooks information and help&lt;/a&gt; page, &amp;quot;Adobe eReader&amp;quot; books
enable you &amp;quot;to read high-fidelity ebooks alongside other PDF files. Only this
reader software displays ebooks with the pictures, graphics, and rich fonts
you've come to expect from printed books.&amp;quot;  While &amp;quot;Adobe Digital Editions&amp;quot; is
&amp;quot;Adobe's reader designed for eBooks&amp;quot; and &amp;quot;uses a format based on the Open
Publishing Standard with the extension .epub,&amp;quot; but &amp;quot;ADE will also display your
PDF files in a double-page, single page, or fit-to-width view &#8212; or you can
specify your own custom fit.&amp;quot;  Both formats have software download links, which
both redirect to Adobe's current Digital Editions page.&lt;/p&gt;

&lt;p&gt;So.  Er.  I think &amp;quot;Adobe eReader&amp;quot; is PDF and &amp;quot;Adobe Digital Editions&amp;quot; is EPUB.
Format proliferation is bad enough without making format identification more
difficult than necessary.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Creative Reformation</title>
    <link href="http://platypope.org/blog/2010/2/3/creative-reformation" rel="alternate"/>
    <id>urn:uuid:191c4f0c-1137-11df-a749-aa008bfedbfd</id>
    <updated>2010-02-03T21:47:19-05:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;Faruk Ates responds to Mark Pilgrim's &lt;a href="http://diveintomark.org/archives/2010/01/29/tinkerers-sunset"&gt;Tinker's Sunset&lt;/a&gt; by trivializing tinkering
and claiming that the ease-to-use devices like the iPad are fostering a
&lt;a href="http://farukat.es/journal/2010/02/390-the-creative-revolution"&gt;Creative Revolution&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;The simple matter is that these guys are old,
and they grew up in an age where tinkering was the only possible course of
action if you wanted to use the latest and greatest technology to its fullest
potential.  The Mac, in 1984, shifted that paradigm of creativity and creation
towards average consumers a little. The iPhone and iPad are shifting it even
further towards consumers, away from the tinkerers of old, the small little
&amp;quot;elite&amp;quot; that excludes the vast majority of
people.&lt;/blockquote&gt;

&lt;p&gt;He may be right about fostering creativity, but he's missing the point.  Making
the iPad accessible to non-tinkers and making it untinkerable are completely
orthogonal.&lt;/p&gt;

&lt;p&gt;Imagine that the iPad worked exacly as Apple has already presented, but it also
had a &amp;quot;tinker&amp;quot; switch. When on, this switch allowed users to run applications
not signed by Apple, with appropriately dire warnings.  Problem solved, without
impacting typical user experience.&lt;/p&gt;

&lt;p&gt;&amp;quot;Tinkering&amp;quot; is easy to trivialize, but doing so ignores what its prevention
represents technically.  What we're talking about on the iPad is an
impenetrable cryptographic shield which gives Apple absolute control over what
code is allowed to run.  Apple, not users, determines what applications are
appropriate.  Apple is free to censor not only content which fails to meet
their technical standards, but also content which conflicts with their business
interests or they deem to be &amp;quot;obscene.&amp;quot;  No matter how light the shackles, on
the iPad (and iPhone) you are not free.&lt;/p&gt;

&lt;p&gt;On the flip side, like Pilgrim I do see &amp;quot;tinkering&amp;quot; as valuable in itself.
Software stacks more than any other engineered systems are inherently knowable,
and one can learn from them.  Fully free systems (in Stallman's sense) are the
most knowable and most instructive by virtue of the source code for every
component being there for the asking.  With a cryptographically shielded
platform like the iPad this is impossible, and the system is unknowable and
there is nothing to be learned even for the &amp;quot;elite.&amp;quot;&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>The vicious cycle of piracy?</title>
    <link href="http://platypope.org/blog/2010/2/3/the-vicious-cycle-of-piracy" rel="alternate"/>
    <id>urn:uuid:001f6b18-1134-11df-a749-aa008bfedbfd</id>
    <updated>2010-02-03T21:23:28-05:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;A few years ago I discovered that Wizards of the Coast had started selling PDF
versions of pretty much the entire catalog of TSR-published original D&amp;amp;D, AD&amp;amp;D,
and AD&amp;amp;D 2nd Ed material, all at quite reasonable prices.  I've been fond of
the &lt;a href="http://en.wikipedia.org/wiki/Planescape"&gt;Planescape&lt;/a&gt; setting ever since I was first introduced to it, and I
impulsively bought the majority of the AD&amp;amp;D 2nd Ed Planescape manuals.  You
known, in case I ever get suddenly transported back to the 90's or something.
I later lost those precious, fully-paid-for bits in a hard drive crash, and
didn't bother redownloading them again because of reasons which seemed
reasonable at the time.  I mean, the vendor I bought them from will surely let
them download them again whenever I decide to.  What could possibly go wrong?&lt;/p&gt;

&lt;p&gt;Fast forward to the present.  Finally setting up a reasonable backup scheme
jogged my memory of previously lost bits, and I decided to try downloading new
copies of those RPG manuals.  And... &lt;a href="http://rpg.drivethrustuff.com/"&gt;the vendor&lt;/a&gt; still exists... I'm able to log
in... they have my complete order history... they have download links!... and
&amp;mdash; no.  Apparently WotC pulled the plug, stopping all e-book sale of their both
current and out-of-print material, including re-downloads of already-sold
titles.&lt;/p&gt;

&lt;p&gt;Of course, a quick search turned up Rapidshare-hosted copies of all the books
I'd purchased, which I felt no scruples about downloading.  But chicken or egg
&amp;mdash; are the books so easily available because WotC removed them from legitimate
channels?  Or was the pull in the first place a response to widespread piracy?
Either way, I don't see how WotC is benefiting.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Solving puzzles with (computer) science</title>
    <link href="http://platypope.org/blog/2010/1/7/solving-puzzles-with-computer-science" rel="alternate"/>
    <id>urn:uuid:e82c3692-fb9b-11de-a749-aa008bfedbfd</id>
    <updated>2010-01-07T14:01:02-05:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;For Christmas my girlfriend gave me a series of increasingly difficult
wooden-block puzzles, yielding up each one only as I solved the previous.
She'd show me the assembled puzzle &amp;mdash; to mock me, I assume &amp;mdash; then dump it
disassembled into my lap&lt;a class="footref" href="#fn.36.1"&gt;1&lt;/a&gt;.  The first one was a quickly-solved freebie, but
the remaining three were pretty difficult.  Difficult enough even that I
decided to let computers do the boring work and wrote programs to solve them.
Ah, the joys of being a software engineer!&lt;/p&gt;

&lt;p&gt;And if you think this is &amp;quot;cheating,&amp;quot; I feel the final results from my &amp;quot;bonus
round&amp;quot; (at the end of this post) validate the approach.&lt;/p&gt;

&lt;p&gt;Round 1 was the &lt;a href="http://paxpuzzle.com/king-snake-medium-p-265.html"&gt;King Snake&lt;/a&gt;.  This puzzle is a 4x4x4 cube composed of 64
linearly connected unit-cubes.  The strand of unit-cubes is divided into 46
segments of 2-4 cubes each.  Each segment shares a joint cube with its previous
segment and freely rotates to form any right angle with that segment.  A naive
estimation of the problem space is greater than 1e27 (4 right-angles to the
power of 46 segments).  However, most moves eliminate 25-75% of the remaining
problem space by either running into already-filled space or leaving the
allowed 4x4x4 grid.  Counting on the constraints quickly reducing the problem
space, I initially solved this one with a pretty naive depth-first search
written in Python.&lt;/p&gt;

&lt;p&gt;The Python program took about 5 hours to run, and was designed to find only one
solution.  But hey! &amp;mdash; it worked and found &lt;a href="http://platypope.org/files/snake-solution-initial.txt"&gt;a solution&lt;/a&gt;.  I later revisited this
puzzle with what I learned from solving the others, but I'll get to that at the
end.&lt;/p&gt;

&lt;p&gt;Round 2 was the &lt;a href="http://www.creativecrafthouse.com/index.php?main_page=product_info&amp;amp;products_id=278"&gt;Shipper's Dilemma Z&lt;/a&gt;.  This puzzle is a 5x5x5 cube composed of
25 identical, 5-unit-cube, vaguely Z-shaped pieces.  For this one I did some
research, hoping something about tessellation would help.  Alas, even though
the pieces are all identical, it appears that this is still an (NP-complete)
packing problem.  There are 960 positions a piece could occupy within the
space, which for 25 pieces yields a naive complexity estimate of greater than
1e49&lt;a class="footref" href="#fn.36.2"&gt;2&lt;/a&gt;.  Ouch.  It seemed much less likely in this case that the basic problem
constraints would help much, as a naive depth-first search would prune only a
few possibilities with each move.  I wrote a simple first-try in Python anyway.
It got absolutely nowhere, which led me to decide to try something different,
something &amp;quot;clever.&amp;quot;  And thus down a rabbit-hole I went.&lt;/p&gt;

&lt;p&gt;I'll leave out most of the details, but I wasted a lot of holiday time trying
to solve this puzzle with something akin to &lt;a href="http://en.wikipedia.org/wiki/Dynamic_programming"&gt;dynamic programming&lt;/a&gt;.  I'd build
groups of 3 pieces &amp;quot;attached&amp;quot; to a vertex, combine those into groups of 6
pieces attached to a quadrant, combine those into group of 12 attached to a
side, then combine those into groups of 24 which (for solutions) would
(theoretically) form the full cube with one piece-shaped hole somewhere in the
middle.  It was a terrible, terrible idea.  The computational complexity of
each step varied wildly as I changed my methods for forming groups and what
assumptions I made about the properties of solution-participating groups.  At
one point the execution-time was lagging &lt;em&gt;just&lt;/em&gt; enough that I re-wrote the
solution-grinding code in C.  Later the complexity was &lt;em&gt;just&lt;/em&gt; where it wasn't
feasible to run at home, but I could run it on &lt;a href="http://aws.amazon.com/elasticmapreduce/"&gt;Amazon's Elastic MapReduce&lt;/a&gt;.  I
did learn how to use Hadoop, EC2, and EMR, but &amp;mdash; long story short &amp;mdash; none of
it yielded a solution.  I eventually climbed out of the rabbit-hole and went
back to a depth-first search, but this time with a much better
conceptualization of the problem.&lt;/p&gt;

&lt;p&gt;Fast C primitives help&lt;a class="footref" href="#fn.36.3"&gt;3&lt;/a&gt;, but the only real way to solve a problem of this
sort is by exponentially reducing the search space.  The first step is to avoid
working on any &amp;quot;unsolvable&amp;quot; states.  Many patterns of piece-placement leave
gaps which no subsequent piece can fill.  I test for this by filling in a copy
of the board state with all the pieces which &lt;em&gt;could&lt;/em&gt; fit, even if those pieces
themselves overlap.  If the cube isn't completely filled, then the initial
board state cannot lead to a solution.&lt;/p&gt;

&lt;p&gt;Another obvious step for any sort of space-pattern problem is to eliminate all
rotations and reflections which result in other states in the same symmetry
group.  For a cubical puzzle like this one, eliminating symmetries reduces the
state-space by &lt;a href="http://www.ams.org/featurecolumn/archive/cubes7.html"&gt;a factor of 48&lt;/a&gt;.  In this case, I did so by initially calculating
all symmetrically unique states which have 8 pieces placed, one in each corner.
This also has the nice side-effect of splitting the search-space into
parallelizable segments, although that turned out to be unnecessary.&lt;/p&gt;

&lt;p&gt;The final step necessary to explore all the &amp;quot;interesting&amp;quot; states in a
reasonable amount of time is to eliminate the exploration of duplicate states.
Just naively iterating over piece combinations will result in trying both piece
A then B and piece B then A, even though they result in exploring the same
board states.  I iterated over a couple approaches to this, but eventually hit
upon simply ensuring that each position in the puzzle is filled in a fixed
sequence.  This minimizes the number of options available for each placement
and doesn't require any explicit book-keeping to short-circuit
previously-explored board states.&lt;/p&gt;

&lt;p&gt;Final running-time: 2.5 minutes to generate &lt;a href="http://platypope.org/files/shipz-solution.txt"&gt;all four solutions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Round 3 was the &lt;a href="http://paxpuzzle.com/ramu-octahedron-p-347.html"&gt;RAMU OCTAHEDRON&lt;/a&gt;&lt;a class="footref" href="#fn.36.4"&gt;4&lt;/a&gt;.  This one is kind of a irregular
decahedron&lt;a class="footref" href="#fn.36.5"&gt;5&lt;/a&gt; represented as a 5x5x5 cube with the 4 unit-cubes at each vertex
removed.  It splits into 8 very irregularly-shaped pieces.  There are also two
small wooden spheres which occupy unfilled space within the cube and &amp;quot;lock&amp;quot; it
by preventing motion of the &amp;quot;key&amp;quot; piece unless the spheres are shifted into
particular positions.  The site calls the Ramu Octahedron their &amp;quot;most difficult
puzzle&amp;quot; and claims that only one person has solved it without reference to the
solution.  The difficulties of this puzzle are three-fold: the irregularity of
the pieces makes conceptualizing their spatial placement difficult; many of the
pieces can only be placed by combinations of separate &amp;quot;insertion&amp;quot; then
&amp;quot;locking&amp;quot; motions; and once the puzzle is assembled, one must determine how to
maneuver the spheres within the unfilled internal space to allow
re-disassembly.&lt;/p&gt;

&lt;p&gt;Fortunately the piece-irregularity holds little difficulty for a computer.
After laboriously entering the shapes of each piece, I was able to re-use code
I'd written for the previous puzzle to generate all the interesting piece
rotations and translations&lt;a class="footref" href="#fn.36.6"&gt;6&lt;/a&gt; and their various combinations.  Once that gave
me the solution spatial arrangement, it required a bit of trial-and-error to
figure out a working piece order and insert/lock sequences, but I was able to
manage it by hand.  Figuring out the necessary unlocking rotations was also
easy enough, at least after I added a map of the unfilled internal space to the
solution.&lt;/p&gt;

&lt;p&gt;Final running-time: 1 second to generate &lt;a href="http://platypope.org/files/ramu-solution.txt"&gt;the single solution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Bonus round, back to the King Snake.  I decided to come back to this puzzle
with what I'd learned from solving the others and try to generate all its
solutions in a reasonable amount of time.  I didn't have any new ideas about
how to frame the puzzle, but I did have some new implementation tools:
pre-generating and indexing by position all legal piece arrangements, and
representing puzzle states as bit-fields.  These two together allow for a
blazing-fast solution.&lt;/p&gt;

&lt;p&gt;Final running-time: 30 seconds to generate &lt;a href="http://platypope.org/files/snake-solution.txt"&gt;all four solutions&lt;/a&gt;&lt;a class="footref" href="#fn.36.7"&gt;7&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you own this puzzle, you may at this point be thinking &amp;quot;Wait, what?&amp;quot;  The
marketing copy and provided instructions for the King Snake claim there are
only &lt;em&gt;two&lt;/em&gt; solutions.  But nope, four.  The two extras solutions are very similar
to each other, but are quite distinct from the two &amp;quot;official&amp;quot; solutions, and
none are simply symmetries of the others.&lt;/p&gt;

&lt;p&gt;&amp;quot;Cheating&amp;quot; &amp;mdash; hah!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://platypope.org/files/puzzles.tar.gz"&gt;Puzzle-solving code&lt;/a&gt; available for your edification.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.36.1"&gt;1&lt;/a&gt;   Best Christmas present ever, seriously.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.36.2"&gt;2&lt;/a&gt;   For comparison, &lt;a href="http://en.wikipedia.org/wiki/Chess#Mathematics_and_computers"&gt;chess&lt;/a&gt; apparently has between 1e43 and 1e50 legal board
states.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.36.3"&gt;3&lt;/a&gt;   Most actions on a the puzzle-state are just a few bitwise operations.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.36.4"&gt;4&lt;/a&gt;   Which I &lt;em&gt;really&lt;/em&gt; like putting in all caps, for some reason.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.36.5"&gt;5&lt;/a&gt;   Yeah, the name confuses me too.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.36.6"&gt;6&lt;/a&gt;   But not reflections, what with three dimensional limitation and all.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.36.7"&gt;7&lt;/a&gt;   FYI, I number from the opposite end than the provided solutions.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Language Implementation Patterns</title>
    <link href="http://platypope.org/blog/2009/10/5/language-implementation-patterns" rel="alternate"/>
    <id>urn:uuid:df7e5fea-b1e8-11de-a749-aa008bfedbfd</id>
    <updated>2009-10-05T16:01:55-04:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;Possible lesson: don't get upset with a book for not being a completely
different book the author hasn't written yet, but will later.&lt;/p&gt;

&lt;p&gt;I few months ago I bought &lt;a href="http://www.pragprog.com/titles/tpantlr/the-definitive-antlr-reference"&gt;The Definitive ANTLR Reference&lt;/a&gt; by Terence Parr&lt;a class="footref" href="#fn.35.1"&gt;1&lt;/a&gt;.
The book's subtitle is &amp;quot;Building Domain-Specific Languages,&amp;quot; so I was rather
disappointed when I found out that it has absolutely no information on building
domain-specific languages &amp;mdash; or any other applications &amp;mdash; using ANTLR.  It's a
great ANTLR reference, but doesn't have any examples of using ANTLR to do
anything other than &lt;em&gt;just&lt;/em&gt; parse (and emit and handle parsing errors).  Without
any practical examples, it took bit of head-scratching on my part to realize
how to even e.g. make my Z-code assembler available to my ANTLR-generate AST
walker.&lt;/p&gt;

&lt;p&gt;But today I learned that Terence Parr has also written another book titled
&lt;a href="http://www.pragprog.com/titles/tpdsl/language-implementation-patterns"&gt;Language Implementation Patterns&lt;/a&gt;. I haven't had a chance to read much of it
yet, but it looks like exactly what I wanted in the first place &amp;mdash; a guide to
actually writing various sorts of applications which involve parsing languages,
mostly using ANTLR-generated parsers.  This book has the oddly-similar subtitle
&amp;quot;Create Your Own Domain-Specific and General Programming Languages,&amp;quot; but which
seems rather more apt here. In any case, I'm looking forward to it.&lt;/p&gt;

&lt;p&gt;And on a side note, Parr's publisher, &lt;a href="http://www.pragprog.com/"&gt;the Pragmatic Bookshelf&lt;/a&gt;, kicks ass.
Their e-book deployment is even better than O'Reilly's.  While both provide
PDF, Mobipocket, and EPUB versions for perpetual re-download, the PragProgs
also (a) offer almost their entire catalog as e-books, and (b) make e-book
editions available as &amp;quot;&lt;a href="http://www.pragprog.com/frequently-asked-questions/beta-books"&gt;beta books&lt;/a&gt;&amp;quot; several months prior to the print release
date.  In fact, &lt;em&gt;Language Implementation Patterns&lt;/em&gt; is currently only available in
an e-book beta version.  But available it is, for delicious pre-final-draft
reading by the adventurous.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.35.1"&gt;1&lt;/a&gt;   Primary author of ANTLR, so you can see the draw.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Testing</title>
    <link href="http://platypope.org/blog/2009/10/1/unstable" rel="alternate"/>
    <id>urn:uuid:d5793ebe-ae84-11de-a749-aa008bfedbfd</id>
    <updated>2009-10-01T08:35:35-04:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;I have to admit there are times when running Debian testing bites me.  Like
today, when I had to reboot my computer, and when it comes back up, all my X
keycodes had changed &amp;mdash; scrambling my custom key mappings across random other
keys &amp;mdash; and tapping on my touchpad no longer worked&lt;a class="footref" href="#fn.34.1"&gt;1&lt;/a&gt;.  Le sigh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Ah, and now it works, via &lt;code&gt;TapButton1&lt;/code&gt;.  Just not when I set it in my
&lt;code&gt;xorg.conf&lt;/code&gt;, only by &lt;code&gt;synclient&lt;/code&gt;.  So now I just need to never reboot again.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.34.1" id="fn.34.1"&gt;1&lt;/a&gt;  &lt;code&gt;TapButton1&lt;/code&gt; had become &amp;quot;0&amp;quot;. I reset it to &amp;quot;1&amp;quot;, but that doesn't seem to have
improved matters.  At least I have buttons I can click in the meantime.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>ZmForth!</title>
    <link href="http://platypope.org/blog/2009/9/29/zmforth" rel="alternate"/>
    <id>urn:uuid:93b114b8-acf2-11de-a749-aa008bfedbfd</id>
    <updated>2009-09-29T08:31:30-04:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;Some time ago I decide to fix one of the holes in my software engineering
knowledge and learn about writing compilers.  My undergraduate curriculum
provided an overview of parsing and some general programming language design
issues, but nothing at all on code generation or optimization.  I bought a few
books on compilers, started familiarizing myself with &lt;a href="http://www.antlr.org/"&gt;ANTLR&lt;/a&gt;, then became
completely and utterly side-tracked by the programming language Forth.&lt;/p&gt;

&lt;p&gt;Forth is a strange little language.  Chance are that unless you're an
astronomer or have mucked around with Sun's OpenBoot, you've never even heard
of it; or if you have heard of it, you've never used it.  Forth saw its heyday
during the 80's and has largely faded away with the 8- and 16-bit processors to
which it was most suited.  But boy was it suited to those processors &amp;mdash; if I
ever needed to develop code to run on a 16-bit processor with less than 128k of
RAM, Forth is probably the language I'd turn to.&lt;/p&gt;

&lt;p&gt;Forth's key property is that it's a purely stack-based language.  Forth
functions &amp;mdash; or &amp;quot;words,&amp;quot; as Forth calls them &amp;mdash; do not take arguments
explicitly, but instead implicitly via a system-wide parameter stack.  There
aren't any local variables &amp;mdash; instead the language provides a rich set of
stack-manipulation primitives like &lt;code&gt;DUP&lt;/code&gt;&lt;a class="footref" href="#fn.33.1"&gt;1&lt;/a&gt;, &lt;code&gt;SWAP&lt;/code&gt;&lt;a class="footref" href="#fn.33.2"&gt;2&lt;/a&gt;, and &lt;code&gt;ROT&lt;/code&gt;&lt;a class="footref" href="#fn.33.3"&gt;3&lt;/a&gt; to facilitate
juggling the top handful of stack items to provide the correct parameters to
each function call.  Even &lt;em&gt;control structures&lt;/em&gt; are implemented with Forth-level
function calls!&lt;a class="footref" href="#fn.33.4"&gt;4&lt;/a&gt; This means that a Forth program consists of nothing more
than a list of functions to call in sequence, a feature which the language
exploits in two ways.&lt;/p&gt;

&lt;p&gt;First, to simplify syntax.  Just as a Forth program abstractly consists of
nothing more than a list of function &amp;quot;words,&amp;quot; the source code of a Forth
program consists of just lists of those words' human-readable names separated
by spaces.  Adding the ability to switch the Forth system between executing
each word as parsed and appending it into a new definition allows the system to
act as both interpreter and compiler in one.  That's a full interactive
interpreter and compiler in under 8k.&lt;/p&gt;

&lt;p&gt;Second, to simplify implementation.  There are &amp;quot;traditional&amp;quot; optimizing
compilers for Forth, but that isn't the most common or most obvious approach to
Forth compilation, especially in-target.  More frequently, Forth systems will
use an approach known as &amp;quot;&lt;a href="http://en.wikipedia.org/wiki/Threaded_code"&gt;threaded code&lt;/a&gt;.&amp;quot;  This has nothing to do with
multithreaded execution, but instead refers to the technique of generating code
which consists of only of calls to other functions.  The more specific
techniques of so-called &amp;quot;direct&amp;quot; and &amp;quot;indirect&amp;quot; threaded code drop even the
calls themselves&lt;a class="footref" href="#fn.33.5"&gt;5&lt;/a&gt; and instead encode only the function addresses.  A list of
address can't be executed directly, so this necessitates an &amp;quot;inner interpreter&amp;quot;
to load and call each in sequence, but this interpreter need only be a few
machine instructions long, and on some architectures imposes no additional
overhead over directly-expressed function calls.  In a Forth system using this
approach, compiling a function call into a new definition literally consists of
just appending the address of the function to call to the end of the definition
in progress.  It just can't get any simpler than that.&lt;/p&gt;

&lt;p&gt;And because it's all so simple, you can implement it yourself!  Or rather, &lt;em&gt;I&lt;/em&gt;
can lose the thin thread of sanity and decide to implement one &lt;em&gt;myself&lt;/em&gt;.  There
are existing F/OSS Forth systems out there for pretty much every environment
under the sun, which provide plenty of examples to turn to for inspiration, but
also mean that the whole Forth thing is pretty well done.  This needn't be a
hindrance to implementation-as-a-learning-exercise, but I wanted to contribute
something new.  I happened to think of the &lt;a href="http://en.wikipedia.org/wiki/Z-machine"&gt;Z-machine&lt;/a&gt;, and lo-and-behold,
although there is &lt;a href="http://www.ifwiki.org/index.php/Lists_and_Lists"&gt;a Z-machine scheme implementation&lt;/a&gt;, there was no Z-machine
Forth.&lt;/p&gt;

&lt;p&gt;Until now!  Ladies and gentlemen, I present to you &lt;a href="http://code.google.com/p/zmforth/"&gt;ZmForth!&lt;/a&gt;, an ANS Forth
implementation for the Z-machine.  It passes the woefully incomplete ANS Forth
test suite I found and runs existing Forth programs that don't depend on file
I/O.  It plays Tetris, performs 32-bit arithmetic and unsigned comparisons, and
provides exceptions, a compiler, and a de-compiler.  All of this in a 16-bit
virtual machine with only 64k of addressable memory.  The whole project was one
giant rabbit hole, but I had to write &lt;a href="http://code.google.com/p/zmforth/source/browse/zas.py"&gt;my own Z-code assembler&lt;/a&gt; to provide the
directives I wanted, which is at least in the direction of what I initially
planned to work on.&lt;/p&gt;

&lt;p&gt;I had a good time working it, and I hope someone else may be at least half as
entertained by it as I was.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.33.1" id="fn.33.1"&gt;1&lt;/a&gt;  Duplicate the stop stack item.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.33.2" id="fn.33.2"&gt;2&lt;/a&gt;  Swap the top two stack items.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.33.3" id="fn.33.3"&gt;3&lt;/a&gt;  Rotate the third stack item to the top.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.33.4" id="fn.33.4"&gt;4&lt;/a&gt;  In fact, in my system all the control structures are implemented &lt;em&gt;in Forth&lt;/em&gt;.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.33.5" id="fn.33.5"&gt;5&lt;/a&gt;  The call instructions, that is.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>An example of why Ruby is no longer my LoC</title>
    <link href="http://platypope.org/blog/2009/7/10/an-example-of-why-ruby-is-no-longer-my-loc" rel="alternate"/>
    <id>urn:uuid:cac75bcc-6da2-11de-8227-aa008bfedbfd</id>
    <updated>2009-07-10T18:41:22-04:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;The &lt;code&gt;Numeric#zero?&lt;/code&gt; method returns &lt;code&gt;true&lt;/code&gt; if the number is &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; if it is
not.  The &lt;code&gt;Numeric#nonzero?&lt;/code&gt; method returns &lt;code&gt;nil&lt;/code&gt; if the number is &lt;code&gt;0&lt;/code&gt; and the number
itself if it is not.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Creator vs. reader and the Adobe EPUB monopoly</title>
    <link href="http://platypope.org/blog/2009/7/2/creator-vs-reader-and-the-adobe-epub-monopoly" rel="alternate"/>
    <id>urn:uuid:9bb44f7a-6735-11de-8227-aa008bfedbfd</id>
    <updated>2009-07-02T14:32:50-04:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;I've been doing a fair bit more reading on my Android phone, although recently
I've switched from &lt;a href="http://www.fbreader.org/FBReaderJ/"&gt;FBReaderJ&lt;/a&gt; to &lt;a href="http://www.aldiko.com/"&gt;Aldiko&lt;/a&gt;.  Each new release of FBReaderJ has
gotten better, but Aldiko includes an actual CSS-based renderer&lt;a class="footref" href="#fn.31.1"&gt;1&lt;/a&gt; and
presently provides a much smoother reading experience&lt;a class="footref" href="#fn.31.2"&gt;2&lt;/a&gt;.  I feel a little
guilty using a piece of commercial software when a free-as-in-freedom solution
exists, but not yet guilty enough to try hacking on FBReaderJ.&lt;/p&gt;

&lt;p&gt;Guilt aside, reading more on a smaller screen has had me thinking again about
the tension between book creator and reader in e-book formatting and layout.
EPUB on the mobile phone highlights this tension more than e-ink devices if for
no other reason than that a phone screen even less resembles a book page than
an e-ink screen does.  One conclusion I've come to is that it's somewhat
unfortunate that Adobe has thus far been the biggest contributor to EPUB as a
commercial e-book format.&lt;/p&gt;

&lt;p&gt;On the one hand, someone had to do it, and it's good that someone has done it.
Even the DRM thing, to some degree &amp;mdash; most publishers aren't ready to do
without it, and at least Adobe had the good grace to use
&lt;a href="http://i-u2665-cabbages.blogspot.com/2009/02/circumventing-adobe-adept-drm-for-epub.html"&gt;an easily circumventable system&lt;/a&gt;.  The major concern I have is with some aspects
of the apparent mindset behind Adobe Digital Editions.&lt;/p&gt;

&lt;p&gt;At present, Digital Editions is the EPUB viewer to beat &amp;mdash; I have no idea what
the actual usage figures look like, but it's the only viewer one can legally
use for all those commercially-sold Adobe-DRMed EPUB books, so one has to
imagine that DE commands the lion's share of the market.  Adobe represents
Digital Editions as being more than just an EPUB viewer.  The advertising copy
on &lt;a href="http://www.adobe.com/products/digitaleditions/"&gt;the DE web site&lt;/a&gt; touts it as &amp;quot;offer[ing] an engaging way to view and manage
eBooks and other digital publications.&amp;quot;  To this end, DE supports not only
EPUB, but also the document format much more central to Adobe's business &amp;mdash;
PDF.  And because PDF is so much more important to Adobe, DE caters to PDF at
the expense of EPUB.&lt;/p&gt;

&lt;p&gt;It's no surprise to the average e-book enthusiast that PDF's fixed-page nature
makes it a poor e-book format.  The most obvious reason is that PDF files can't
be cleanly reflowed to alternative page sizes.  A perhaps less obvious
corollary is that PDF leaves little room for user control of basic formatting
parameters such as font size, line height, text alignment, and paragraph
marking.  But via one or more chains of causality, because PDF rendering does
not allow user-control of these properties, Adobe DE doesn't allow setting them
for EPUB either.  This yields an EPUB viewer where the reader has control over
only the font size and page size.  And even then only partial control! &amp;mdash; DE
will not rescale any size a book specifies as an absolute size, and DE allows
books to provide &amp;quot;page template&amp;quot; files which control how the available screen
area is divided into text regions and body columns.&lt;/p&gt;

&lt;p&gt;The most generous interpretation of this decision is interface consistency.  As
long as Adobe is attempting to present PDF as an e-book format and provide a
viewer which handles &amp;quot;digital publications&amp;quot; regardless of format, it only
complicates that viewer's interface to provide options which apply to some
formats but not others.  Somewhat less charitably, Adobe's focus on PDF may
have led to an unconscious bias toward creator control of document formatting,
to the extent of perhaps not even considering placing control beyond font size
(a.k.a. &amp;quot;zoom&amp;quot;) in the readers' hands.  And way over on the conspiracy-theory
side of the fence, perhaps it represents a conscious decision on the part of
Adobe to limit the usefulness (and adoption) of EPUB by making it only a small
improvement over PDF even for the documents most suited to reflowable
formatting.&lt;/p&gt;

&lt;p&gt;So for whatever reason, the most popular EPUB viewer on the market has
limitations which severely restrict the usefulness of the format.  But EPUB is
an open standard, which means other, better viewers are free to compete with
Digital Editions and supplant it, right?  Except they aren't really, because of
DRM.&lt;/p&gt;

&lt;p&gt;As I mentioned above, it seems that most publishers are not yet ready to do
without DRM, despite the lesson of the music industry.  The overwhelming
majority of commercially-sold books are encumbered with DRM, and all of the
DRM-encumbered EPUB books sold use Adobe's ADEPT DRM.  It would be technically
possible for a competitor to begin offering a different EPUB DRM scheme, but I
can only imagine the degree of confusion mutually incompatible &amp;quot;EPUB&amp;quot; books
would cause among average consumers.  So any successful EPUB viewer device or
application needs to license the ADEPT DRM technology from Adobe.&lt;/p&gt;

&lt;p&gt;To facilitate this, Adobe has begun offering the &amp;quot;&lt;a href="http://www.adobe.com/devnet/readermobile/"&gt;Adobe Reader Mobile 9 SDK&lt;/a&gt;.&amp;quot;
The SDK is available by license agreement only&lt;a class="footref" href="#fn.31.4"&gt;4&lt;/a&gt;, so we can but speculate from
the marketing copy on the capabilities and interfaces it provides.  The
&amp;quot;features&amp;quot; list in the SDK FAQ focuses entirely on features of the &amp;quot;Reader
Mobile document rendering engine,&amp;quot; suggesting that SDK primarily/only provides
a rendering engine.  If this is the case, then Adobe is not expecting &amp;mdash; or
potentially &lt;em&gt;allowing&lt;/em&gt; &amp;mdash; other vendors to write competing ADEPT-compatible EPUB
renderers.  Instead, all the available and announced EPUB reader apps/devices
using the Adobe SDK&lt;a class="footref" href="#fn.31.5"&gt;5&lt;/a&gt; will simply repackage the Adobe renderer and the paucity
of options for user control it provides.&lt;/p&gt;

&lt;p&gt;One example in support of this theory is Amazon's PDF support in the Kindle DX.
Although not widely advertised, &lt;a href="http://blogs.adobe.com/billmccoy/2009/05/amazon_others_l.html"&gt;Amazon is apparently using the Adobe SDK&lt;/a&gt;, just
integrating only the PDF renderer.  Notably missing in the DX's PDF support
vs. all the Kindles' Mobipocket support is the ability to add annotations to
documents.  It seems to me that this would be a &amp;quot;must have&amp;quot; feature, not only
for parity with Mobipocket support, but also for the target market as a device
for textbooks and technical documents.  To me the most obvious explanation for
this feature's lack is that there isn't an easy way to add it while still using
the SDK to allow rendering of DRMed PDFs.  There are plenty F/OSS PDF renderers
to which Amazon could have (comparatively) easily added annotation support,
which suggests that the Adobe SDK's DRM support is an implicit part of the
included renderer, and that SDK licensees cannot use the SDK to read DRMed
documents independently of the renderer.&lt;/p&gt;

&lt;p&gt;Another interesting angle is to compare the Adobe approach with how other book
formats/viewers handle the creator-reader tension.&lt;/p&gt;

&lt;p&gt;The desktop version of MSReader allows setting only the font size, but a
significant number of users seem to regard it as still the best desktop e-book
viewer available.  A major component of this seems to be very well-chosen
defaults for properties like line-height, and the infrequency with which books
alter those properties.  I have seen much more mixed reactions to the Mobile
version, perhaps because on the smaller screens of mobile devices tuning the
line-height, margins, etc to an individually comfortable size is much more
important.  Perhaps a commenter could fill me in?&lt;/p&gt;

&lt;p&gt;The various Mobipocket viewers support differing assortments of user-controlled
properties.  Most support setting font-size, line-height, and paragraph
alignment.  Interestingly, Mobipocket's treatment of these properties
demonstrates all three possible resolutions of the creator-reader formatting
tension.  Line-height may be set by the reader, but not by the book creator &amp;mdash;
the format simply provides no way to specify it.  The font-size may be set by
the book creator, but only in terms of a size relative to the reader-selected
base size.  And paragraph alignment may be specified by either the book creator
or reader, but the creator's setting overrides the reader's when specified.&lt;/p&gt;

&lt;p&gt;Correspondingly, paragraph alignment is the subject of one of Mobipocket's most
forceful formatting recommendations: &amp;quot;alignment must NOT be set if it is not
strictly needed.&amp;quot;  In contrast, the EPUB specification documents contain little
resembling formatting guidelines (beyond an admonition against using absolute
positioning).  The one purely formatting recommendation in Adobe's &amp;quot;EPUB Best
Practices Guide&amp;quot; is &amp;quot;use spacing that looks more like a book,&amp;quot; suggesting
including CSS rules to eliminate default space around block-level elements.  It
does contain some sensible recommendations e.g. against using &lt;br /&gt; tags in
most contexts, but otherwise the &amp;quot;Guide&amp;quot; documents Adobe's EPUB extensions and
DE's quirks more than actual &amp;quot;best practices.&amp;quot;  Which means that EPUB combines
the most extensive e-book formatting capabilities with the fewest guidelines
for producing actually readable books.  And this is something of a challenge
for authors of EPUB viewers.&lt;/p&gt;

&lt;p&gt;Coming full circle to the beginning of this post, the Aldiko EPUB viewer does
allow the user to set some basic formatting properties, including margins,
font, font-size, and line-height&lt;a class="footref" href="#fn.31.6"&gt;6&lt;/a&gt;.  The first three work seamlessly, but
line-height somewhat less so.  Aldiko handles books which don't specify their
own line-height fine, but any book-specified line-height &amp;quot;wins.&amp;quot;  Which isn't
intended as a slight on Aldiko &amp;mdash; this is a difficult problem to solve.&lt;/p&gt;

&lt;p&gt;Something like page margin can really only be set via CSS in one &amp;quot;most
sensible&amp;quot; way&lt;a class="footref" href="#fn.31.7"&gt;7&lt;/a&gt;, and thus is easy to override coherently and consistently in a
viewer.  Font-size is potentially trickier, but the most obvious ways of
specifying font sizes (relative sizes and the CSS named absolute sizes) make a
simple solution fairly straightforward.  Properties like 'line-height'
unfortunately lack such a solution &amp;mdash; all the allowed relative values for the
CSS 'line-height' property are interpreted as relative to the 'font-size', not
the 'line-height' of the parent element.  This means that the font-size
solution of &amp;quot;change the base and respect subsequent relative changes&amp;quot; doesn't
work for line-height.  Without doing some sort of layout analysis, all a viewer
can do is either ignore all book-specified line-heights or respect all
book-specified line heights.&lt;/p&gt;

&lt;p&gt;Solution?  I'm not sure.  One possible solution would be for book producers and
viewer author to agree on guidelines which allow viewers to consistently
override some set of formatting properties.  Most of these could be fairly
simple, like Mobipocket's &amp;quot;alignment must not be set&amp;quot; rule.  Another solution
would be for e-book reader apps to do some sort of pre-rendering layout
analysis which allows them to produce automatically produce a per-book user
stylesheet.  I like hands-off technological solutions, but I'm not sure how
feasible that will be on mobile devices.&lt;/p&gt;

&lt;p&gt;Other ideas?&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.31.1"&gt;1&lt;/a&gt;   To my surprise, a good enough one to handle the 'max-width' property on
images.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.31.2"&gt;2&lt;/a&gt;   Quite literally, in the case of the page-turn animation.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.31.4"&gt;4&lt;/a&gt;   Probably to stop people from reverse-engineering the DRM system.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.31.5"&gt;5&lt;/a&gt;   The ones I'm currently aware of: the Sony Reader, Lexcycle Stanza, the
Bookeen Cybook, and the Elonex ebook.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.31.6"&gt;6&lt;/a&gt;   Not paragraph alignment yet, but via e-mail the author has said it'll
probably be added soon.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.31.7"&gt;7&lt;/a&gt;   One could set left and right margins on every block level element, but
hopefully no one actually does that.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Thoughtcrime Experiments EPUB edition</title>
    <link href="http://platypope.org/blog/2009/5/1/thoughtcrime-experiments-epub-edition" rel="alternate"/>
    <id>urn:uuid:9da222c2-360b-11de-8227-aa008bfedbfd</id>
    <updated>2009-05-01T00:53:14-04:00</updated>
    <author>
      <name>Marshall T. Vandegrift</name>
    </author>
    <content type="html">
&lt;p&gt;This past weekend &lt;a href="http://crummy.com/"&gt;Leonard Richardson&lt;/a&gt; (of BeautifulSoup fame) and Sumana
Harihareswara released &lt;a href="http://thoughtcrime.crummy.com/2009/"&gt;Thoughtcrime Experiments&lt;/a&gt;, a 100% independent, CC
BY-NC-SA 3.0 licensed F/SF anthology.  It's pretty rockin', in both concept and
execution.&lt;/p&gt;

&lt;p&gt;Ararche Jerico beat me to it by a couple days with his
&lt;a href="http://www.spontaneousderivation.com/2009/04/27/free-fiction-thoughtcrime-experiments-for-the-kindle-and-other-devices"&gt;e-book editions of Thoughtcrime Experiments&lt;/a&gt;, but what I lack in speed, I make
up in obsessive-compulsive attention to trivial details.  Thus I present to you
the &lt;a href="http://platypope.org/files/ThoughtcrimeExperiments.epub"&gt;Thoughtcrime Experiments EPUB pedant edition&lt;/a&gt;.  To what sorts of trivial
details does this edition attend?  Glad you asked!:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Book-optimized stylesheet.  I created a new stylesheet for the book from
scratch, roughly following the design of the &lt;em&gt;Thoughtcrime Experiments&lt;/em&gt;
PDF/print edition.  Beyond just looking more &amp;quot;book-like&amp;quot; (paragraphs marked
by indentation rather than vertical whitespace, etc), I've also ensured
that all body text maintains vertical rhythm, lines appearing at the same
positions even following headings, breaks, and so on.&lt;/li&gt;
&lt;li&gt;High-quality art.  Includes higher-quality version of the artwork than used
for the Web edition, providing some degree of future-proofing for larger
e-book reading displays.  I've also taken pains to display the art nicely,
despite the best efforts of the CSS standard to the contrary.&lt;/li&gt;
&lt;li&gt;A beautiful, fully-scalable SVG cover.  Ok, the SVG cover actually looks
like crap / doesn't display at all in everything but AdobeDE.  But it looks
quite nice there, thank you very much.&lt;/li&gt;
&lt;li&gt;Hand-corrected HTML-&amp;gt;XHTML conversion.  The source HTML had a handful of
missing-tag etc. issues.  I individually validated each file and
hand-corrected it, ensuring perfect markup.&lt;/li&gt;
&lt;li&gt;Fully normalized punctuation.  The source HTML contained some variation in
punctuation conventions and handful of punctuation errors (a missing
opening quotation mark, two hyphens instead of an emdash, etc).  I've
corrected the errors and normalized to a single set of conventions.&lt;/li&gt;
&lt;li&gt;Squeaky-clean metadata.  Not only passes &lt;a href="http://code.google.com/p/epubcheck/"&gt;epubcheck&lt;/a&gt;&lt;a class="footref" href="#fn.30.1"&gt;1&lt;/a&gt;, but does so with
panache!  Includes all required metadata, identifies each contributor with
a separate metadata entry, and includes a metadata table of contents which
mimics the structure of the PDF/print edition TOC.&lt;/li&gt;
&lt;li&gt;Embeds a font.  This is a bit of a pet peeve of mine, but the OPS spec
doesn't actually require that EPUB reader systems provide a default set of
glyphs for any particular set of Unicode characters in any particular
typeface.  This means that embedding a font is the only option if you want
to be certain all the characters in your book will display properly.  I
chose TeX Gyre Pagella because it's (a) free-as-in-freedom and (b) looks
nice and &lt;em&gt;sassy&lt;/em&gt;&lt;a class="footref" href="#fn.30.2"&gt;2&lt;/a&gt; at 10 points.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.30.1" id="fn.30.1"&gt;1&lt;/a&gt;  Actually not completely true at the time of writing, due to what appears
to be a bug in NCX validation.&lt;/p&gt;

&lt;p class="footnote"&gt;&lt;a class="footnum" name="fn.30.2" id="fn.30.2"&gt;2&lt;/a&gt;  By which I mean &amp;quot;legible.&amp;quot;&lt;/p&gt;
    </content>
  </entry>
</feed>
