does network address translation. Deploying this application outside a LAN will require some modifications, but if you want to deploy this application to the wider Internet, you'd better know enough about networking to figure out an appropriate scheme yourself.
308
Unfortunately, because of licensing issues around the MP3 format, it's not clear that it's legal for me to provide you with such an MP3 without paying licensing fees to Fraunhofer IIS. I got mine as part of the software that came with my Slimp3 from Slim Devices. You can grab it from their Subversion repository via the Web at http://svn.slimdevices.com/*checkout*/trunk/server/HTML/EN/html/silentpacket.mp3?rev=2
. Or buy a Squeezebox, the new, wireless version of Slimp3, and you'll get silentpacket.mp3
as part of the software that comes with it. Or find an MP3 of John Cage's piece
309
The reader supports a bit of syntax, #.
, that causes the following s-expression to be evaluated at read time. This is occasionally useful in source code but obviously opens a big security hole when you read untrusted data. However, you can turn off this syntax by setting *READ- EVAL*
to NIL
, which will cause the reader to signal an error if it encounters #.
.
310
This solution has its drawbacks—if a browse
page returns a lot of results, a fair bit of data is going back and forth under the covers. Also, the database queries aren't necessarily the most efficient. But it does keep the application stateless. An alternative approach is to squirrel away, on the server side, information about the results returned by browse
and then, when a request to add songs come in, find the appropriate bit of information in order to re-create the correct set of songs. For instance, you could just save the values list instead of sending it back in the form. Or you could copy the RANDOM- STATE
object before you generate the browse results so you can later re-create the same 'random' results. But this approach causes its own problems. For instance, you'd then need to worry about when you can get rid of the squirreled-away information; you never know when the user might hit the Back button on their browser to return to an old browse page and then hit the 'Add all' button. Welcome to the wonderful world of Web programming.
311
In fact, it's probably
312
Well, almost every tag. Certain tags such as IMG
and BR
don't. You'll deal with those in the section 'The Basic Evaluation Rule.'
313
In the strict language of the Common Lisp standard, keyword symbols aren't
314
The requirement to use objects that the Lisp reader knows how to read isn't a hard-and-fast one. Since the Lisp reader is itself customizable, you could also define a new reader-level syntax for a new kind of object. But that tends to be more trouble than it's worth.
315
Another, more purely object-oriented, approach would be to define two classes, perhaps html-pretty- printer
and html-raw-printer
, and then define no-op methods specialized on html-raw-printer
for the methods that should do stuff only when *pretty*
is true. However, in this case, after defining all the no-op methods, you'd end up with more code, and then you'd have the hassle of making sure you created an instance of the right class at the right time. But in general, using polymorphism to replace conditionals is a good strategy.
316
You don't need a predicate for *inline-elements*
since you only ever test for block and paragraph elements. I include the parameter here for completeness.
317
While XHTML requires boolean attributes to be notated with their name as the value to indicate a true value, in HTML it's also legal to simply include the name of the attribute with no value, for example, <option selected>
rather than <option