[bknr-cvs] hans changed trunk/libraries/yason/index.html

BKNR Commits bknr at bknr.net
Sat Nov 15 10:12:08 UTC 2008


Revision: 4050
Author: hans
URL: http://bknr.net/trac/changeset/4050

Add HTML rendered version of the documentation.

A   trunk/libraries/yason/index.html

Added: trunk/libraries/yason/index.html
===================================================================
--- trunk/libraries/yason/index.html	                        (rev 0)
+++ trunk/libraries/yason/index.html	2008-11-15 10:12:08 UTC (rev 4050)
@@ -0,0 +1,477 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>YASON - A JSON encoder/decoder for Common Lisp</title><meta name="description" content="
+    YASON is a JSON encoding and decoding library for Common Lisp.
+    It provides for functions to read JSON strings into Lisp data
+    structures and for serializing Lisp data structures as JSON
+    strings.
+  "></meta><style type="text/css">
+  body { background-color: #ffffff; max-width: 50em; margin-left: 2em; font-family: Georgia, 'Times New Roman', serif; }
+  pre { padding:5px; background-color:#e0e0e0; margin: 1em 2em 1em 2em; }
+  pre.none { padding:5px; background-color:#ffffff; }
+  h3, h4, h5 { text-decoration: underline; }
+  a { text-decoration: none; padding: 1px 2px 1px 2px; }
+  a:visited { text-decoration: none; padding: 1px 2px 1px 2px; }
+  a:hover { text-decoration: none; padding: 1px 1px 1px 1px; border: 1px solid #000000; } 
+  a:focus { text-decoration: none; padding: 1px 2px 1px 2px; border: none; }
+  a.none { text-decoration: none; padding: 0; }
+  a.none:visited { text-decoration: none; padding: 0; } 
+  a.none:hover { text-decoration: none; border: none; padding: 0; } 
+  a.none:focus { text-decoration: none; border: none; padding: 0; } 
+  a.noborder { text-decoration: none; padding: 0; } 
+  a.noborder:visited { text-decoration: none; padding: 0; } 
+  a.noborder:hover { text-decoration: none; border: none; padding: 0; } 
+  a.noborder:focus { text-decoration: none; border: none; padding: 0; }
+  table { margin: 1em; }
+        </style></head><body>
+
+  <h2 xmlns="">YASON - A JSON encoder/decoder for Common Lisp</h2>
+
+  
+
+  <h3 xmlns="">Abstract</h3>
+<blockquote xmlns="">
+    YASON is a Common Lisp library for encoding and decoding data in
+    the <a xmlns="http://www.w3.org/1999/xhtml" href="http://json.org/">JSON</a> interchange format.
+    JSON is used in AJAX applications as a lightweight alternative
+    to XML.  YASON has the sole purpose of encoding and decoding
+    data and does not impose any object model on the Common Lisp
+    application that uses it.
+  </blockquote>
+
+  <h3 xmlns="">Contents</h3>
+<ol xmlns="">
+<li><a href="#intro">Introduction</a></li>
+<li><a href="#install">Installation</a></li>
+<li><a href="#mapping">Mapping between JSON and CL datatypes</a></li>
+<li>
+<a href="#parsing">Parsing JSON data</a><ol><li><a href="#parser-dict">Parser dictionary</a></li></ol>
+</li>
+<li>
+<a href="#encoding">Encoding JSON data</a><ol>
+<li><a href="#dom-encoder">Encoding a JSON DOM</a></li>
+<li><a href="#stream-encoder">Encoding JSON in streaming mode</a></li>
+<li><a href="#app-encoders">Application specific encoders</a></li>
+</ol>
+</li>
+<li><a href="#index">Symbol index</a></li>
+<li><a href="#license">License</a></li>
+<li><a href="#ack">Acknowledgements</a></li>
+</ol>
+
+  <h3 xmlns=""><a class="none" name="intro">Introduction</a></h3>
+    <a href="http://json.org/">JSON</a> is an established alternative
+    to XML as a data interchange format for web applications.  YASON
+    implements reading and writing of JSON formatted data in Common
+    Lisp.  It does not attempt to provide a mapping between CLOS
+    objects and YASON, but can be used to implement such mappings.
+  
+
+  <h3 xmlns=""><a class="none" name="install">Installation</a></h3>
+    <p>
+      YASON has its permanent home
+      at <a href="http://common-lisp.net/project/yason/">common-lisp.net</a>.
+      It can be obtained either by downloading
+      the <a href="http://common-lisp.net/project/yason/files/yason.tar.gz">release
+        tarball</a> or by checking out the current development version
+      from its subversion repository:
+      <pre>svn co svn://bknr.net/svn/trunk/libraries/yason/</pre>
+    </p>
+    <p>
+      YASON is written in ANSI Common Lisp and does not depend on
+      other libraries.
+    </p>
+    <p>
+      YASON lives in the <b>:yason</b> package and creates a package nickname
+      <b>:json</b>.  Applications will not normally <b>:use</b> this
+      package, but rather use qualified names to access YASON's
+      symbols.  For that reason, YASON's symbols do not contain the
+      string "JSON" themselves.  See below for usage samples.
+    </p>
+  
+
+  <h3 xmlns=""><a class="none" name="mapping">Mapping between JSON and CL datatypes</a></h3>
+    By default, YASON performs the following mappings between JSON and
+    CL datatypes:
+    <table border="1">
+      <thead>
+        <tr>
+          <th>JSON<br></br>datatype</th>
+          <th>CL<br></br>datatype</th>
+          <th>Notes</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td>object</td>
+          <td>hash-table<br></br>:test #'equal</td>
+          <td>
+            Keys are strings by default,
+            see <code xmlns=""><a href="#*parse-object-key-fn*">*parse-object-key-fn*</a></code>
+          </td>
+        </tr>
+        <tr>
+          <td>array</td>
+          <td>list</td>
+          <td>
+            Can be changed to read to vectors,
+            see <code xmlns=""><a href="#*parse-json-arrays-as-vectors*">*parse-json-arrays-as-vectors*</a></code>
+          </td>
+        </tr>
+        <tr>
+          <td>string</td>
+          <td>string</td>
+          <td>
+            JSON escape characters are recognized upon reading.
+            Upon writing, known escape characters are used, but
+            non-ASCII Unicode characters are written as is.
+          </td>
+        </tr>
+        <tr>
+          <td>number</td>
+          <td>number</td>
+          <td>
+            Parsed with READ, printed with PRINC.  This is not a
+            faithful implementation of the specification.
+          </td>
+        </tr>
+        <tr>
+          <td>true</td>
+          <td>t</td>
+          <td>Can be changed to read as TRUE, see <code xmlns=""><a href="#*parse-json-booleans-as-symbols*">*parse-json-booleans-as-symbols*</a></code></td>
+        </tr>
+        <tr>
+          <td>false</td>
+          <td>nil</td>
+          <td>Can be changed to read as FALSE, see <code xmlns=""><a href="#*parse-json-booleans-as-symbols*">*parse-json-booleans-as-symbols*</a></code></td>
+        </tr>
+        <tr>
+          <td>null</td>
+          <td>nil</td>
+          <td></td>
+        </tr>
+      </tbody>
+    </table>
+  
+
+  <h3 xmlns=""><a class="none" name="parsing">Parsing JSON data</a></h3>
+    <p>
+      JSON data is always completely parsed into an equivalent
+      in-memory representation.  Upon reading, some translations are
+      performed by default to make it easier for the Common Lisp
+      program to work with the data; see <code xmlns=""><a href="#mapping">mapping</a></code>
+      for details.  If desired, the parser can be configured to
+      preserve the full semantics of the JSON data read.
+    </p>
+
+    For example
+
+    <pre>CL-USER> (defvar *json-string* "[{\"foo\":1,\"bar\":[7,8,9]},2,3,4,[5,6,7],true,null]")
+*JSON-STRING*
+CL-USER> (let* ((result (json:parse *json-string*)))
+           (print result)
+           (alexandria:hash-table-plist (first result)))
+
+(#<HASH-TABLE :TEST EQUAL :COUNT 2 {5A4420F1}> 2 3 4 (5 6 7) T NIL) 
+("bar" (7 8 9) "foo" 1)
+CL-USER> (defun maybe-convert-to-keyword (js-name)
+           (or (find-symbol (string-upcase js-name) :keyword)
+               js-name))
+MAYBE-CONVERT-TO-KEYWORD
+CL-USER> :FOO ; intern the :FOO keyword
+:FOO
+CL-USER> (let* ((json:*parse-json-arrays-as-vectors* t)
+                (json:*parse-json-booleans-as-symbols* t)
+                (json:*parse-object-key-fn* #'maybe-convert-to-string)
+                (result (json:parse *json-string*)))
+           (print result)
+           (alexandria:hash-table-plist (aref result 0)))
+
+#(#<HASH-TABLE :TEST EQUAL :COUNT 2 {59B4EAD1}> 2 3 4 #(5 6 7) YASON:TRUE NIL) 
+("bar" #(7 8 9) :FOO 1)</pre>
+
+    <p>
+      The second example modifies the parser's behaviour so that JSON
+      arrays are read as CL vectors, JSON booleans will be read as the
+      symbols TRUE and FALSE and JSON object keys will be looked up in
+      the <b>:keyword</b> package.  Interning strings coming from an
+      external source is not recommended practice.
+    </p>
+
+    <h4 xmlns=""><a name="parser-dict">Parser dictionary</a></h4>
+      <p xmlns="">[Generic function]<br><a class="none" name="parse"><b>parse</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">input</clix:lambda-list></i>
+          =>
+          <i>object</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+          Parse <code><i>input</i></code>, which needs to be a string
+          or a stream, as JSON.  Returns the lisp representation of the
+          JSON structure parsed.
+        </clix:description></blockquote></p>
+
+      <p xmlns="">
+      [Special variable]<br><a class="none" name="*parse-json-arrays-as-vectors*"><b>*parse-json-arrays-as-vectors*</b></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+          If set to a true value, JSON arrays will be parsed as vectors,
+          not as lists.
+        </clix:description></blockquote></p>
+
+      <p xmlns="">
+      [Special variable]<br><a class="none" name="*parse-json-booleans-as-symbols*"><b>*parse-json-booleans-as-symbols*</b></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+          If set to a true value, JSON booleans will be read as the
+          symbols TRUE and FALSE, not as T and NIL, respectively.
+        </clix:description></blockquote></p>
+
+      <p xmlns="">
+      [Special variable]<br><a class="none" name="*parse-object-key-fn*"><b>*parse-object-key-fn*</b></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+          Function to call to convert a key string in a JSON array to a
+          key in the CL hash produced.
+        </clix:description></blockquote></p>
+    
+  
+
+  <h3 xmlns=""><a class="none" name="encoding">Encoding JSON data</a></h3>
+    YASON provides for two distinct modes to encode JSON data:
+    Applications can either create an in memory representation of the
+    data to be serialized, then have YASON convert it to JSON in one
+    go, or they can use a set of macros to serialze the JSON data
+    element-by-element, thereby having fine grained control over the
+    layout of the generated data.
+
+    <h4 xmlns=""><a name="dom-encoder">Encoding a JSON DOM</a></h4>
+      <p>
+        In this mode, an in-memory structure is encoded in JSON format.
+        The structure must consist of objects that are serializable
+        using the <code xmlns=""><a href="#encode">ENCODE</a></code> function.  YASON defines a
+        number of encoders for standard data types
+        (see <code xmlns=""><a href="#mapping">MAPPING</a></code>), but the application can
+        define additional methods, e.g. for encoding CLOS objects.
+      </p>
+      For example:
+      <pre>CL-USER> (json:encode 
+          (list (alexandria:plist-hash-table
+                 '("foo" 1 "bar" (7 8 9))
+                 :test #'equal)
+                2 3 4
+                '(5 6 7)
+                t nil)
+          *standard-output*)
+[{"foo":1,"bar":[7,8,9]},2,3,4,[5,6,7],true,null]
+(#<HASH-TABLE :TEST EQUAL :COUNT 2 {59942D21}> 2 3 4 (5 6 7) T NIL)</pre>
+
+      <h4 xmlns=""><a name="dom-encoder-dict">DOM encoder dictionary</a></h4>
+        <p xmlns="">[Generic function]<br><a class="none" name="encode"><b>encode</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">object &optional stream</clix:lambda-list></i>
+          =>
+          <i>object</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Encode <code><i>object</i></code>
+            to <code><i>stream</i></code> in JSON format.  May be
+            specialized by applications to perform specific
+            rendering.  <code><i>stream</i></code> defaults to
+            *STANDARD-OUTPUT*.
+          </clix:description></blockquote></p>
+      
+    
+
+    <h4 xmlns=""><a name="stream-encoder">Encoding JSON in streaming mode</a></h4>
+      <p>
+        In this mode, the JSON structure is generated in a stream.
+        The application makes explicit calls to the encoding library
+        in order to generate the JSON structure.  It provides for more
+        control over the generated output, and can be used to generate
+        arbitary JSON without requiring that there exists a directly
+        matching Lisp datastructure.  The streaming API uses
+        the <code xmlns=""><a href="#encode">encode</a></code> function, so it is possible to
+        intermix the two.  See <code xmlns=""><a href="#app-encoders">app-encoders</a></code> for
+        an example.
+      </p>
+      For example:
+      <pre>CL-USER> (json:with-output (*standard-output*)
+           (json:with-array ()
+             (dotimes (i 3)
+               (json:encode-array-element i))))
+[0,1,2]
+NIL
+CL-USER> (json:with-output (*standard-output*)
+           (json:with-object ()
+             (json:encode-object-element "hello" "hu hu")
+             (json:with-object-element ("harr")
+               (json:with-array ()
+                 (dotimes (i 3)
+                   (json:encode-array-element i))))))
+{"hello":"hu hu","harr":[0,1,2]}
+NIL</pre>
+
+      <h4 xmlns=""><a name="stream-encoder-dict">Streaming encoder dictionary</a></h4>
+        <p xmlns="">[Macro]<br><a class="none" name="with-output"><b>with-output</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">(stream) &body body</clix:lambda-list></i>
+          =>
+          <i>result*</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Set up a JSON streaming encoder context
+            on <code><i>stream</i></code>, then
+            evaluate <code><i>body</i></code>.
+          </clix:description></blockquote></p>
+
+        <p xmlns="">[Macro]<br><a class="none" name="with-output-to-string*"><b>with-output-to-string*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">() &body body</clix:lambda-list></i>
+          =>
+          <i>result*</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Set up a JSON streaming encoder context, then
+            evaluate <code><i>body</i></code>.  Return a string with the
+            generated JSON output.
+          </clix:description></blockquote></p>
+
+        <p xmlns="">
+      [Condition type]<br><a class="none" name="no-json-output-context"><b>no-json-output-context</b></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            This condition is signalled when one of the stream encoding
+            function is used outside the dynamic context of a
+            <code><a href="#with-output">WITH-OUTPUT</a></code> or
+            <code><a href="#with-output-to-string*">WITH-OUTPUT-TO-STRING*</a></code> body.
+          </clix:description></blockquote></p>
+
+        <p xmlns="">[Macro]<br><a class="none" name="with-array"><b>with-array</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">() &body body</clix:lambda-list></i>
+          =>
+          <i>result*</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Open a JSON array, then run <code><i>body</i></code>.  Inside
+            the body, <code><a href="#encode-array-element">ENCODE-ARRAY-ELEMENT</a></code> must be
+            called to encode elements to the opened array.  Must be called
+            within an existing JSON encoder context, see
+            <code><a href="#with-output">WITH-OUTPUT</a></code> and
+            <code><a href="#with-output-to-string*">WITH-OUTPUT-TO-STRING*</a></code>.
+          </clix:description></blockquote></p>
+
+        <p xmlns="">[Function]<br><a class="none" name="encode-array-element"><b>encode-array-element</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">object</clix:lambda-list></i>
+          =>
+          <i>object</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Encode <code><i>object</i></code> as next array element to
+            the last JSON array opened
+            with <code><a href="#with-array">WITH-ARRAY</a></code> in the dynamic
+            context.  <code><i>object</i></code> is encoded using the
+            <code><a href="#encode">ENCODE</a></code> generic function, so it must be of
+            a type for which an <code><a href="#encode">ENCODE</a></code> method is
+            defined.
+          </clix:description></blockquote></p>
+
+        <p xmlns="">[Macro]<br><a class="none" name="with-object"><b>with-object</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">() &body body</clix:lambda-list></i>
+          =>
+          <i>result*</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Open a JSON object, then run <code><i>body</i></code>.  Inside the body,
+            <code><a href="#encode-object-element">ENCODE-OBJECT-ELEMENT</a></code>
+            or <code><a href="#with-object-element">WITH-OBJECT-ELEMENT</a></code> must be called to
+            encode elements to the object.  Must be called within an
+            existing JSON encoder context,
+            see <code><a href="#with-output">WITH-OUTPUT</a></code>
+            and <code><a href="#with-output-to-string*">WITH-OUTPUT-TO-STRING*</a></code>.
+          </clix:description></blockquote></p>
+
+        <p xmlns="">[Macro]<br><a class="none" name="with-object-element"><b>with-object-element</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">(key) &body body</clix:lambda-list></i>
+          =>
+          <i>result*</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Open a new encoding context to encode a JSON object
+            element.  <code><i>key</i></code> is the key of the element.
+            The value will be whatever <code><i>body</i></code>
+            serializes to the current JSON output context using one of the
+            stream encoding functions.  This can be used to stream out
+            nested object structures.
+          </clix:description></blockquote></p>
+
+        <p xmlns="">[Function]<br><a class="none" name="encode-object-element"><b>encode-object-element</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">key value</clix:lambda-list></i>
+          =>
+          <i>value</i></a><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
+            Encode <code><i>key</i></code> and <code><i>value</i></code>
+            as object element to the last JSON object opened
+            with <code><a href="#with-object">WITH-OBJECT</a></code> in the dynamic
+            context.  <code><i>key</i></code>
+            and <code><i>value</i></code> are encoded using
+            the <code><a href="#encode">ENCODE</a></code> generic function, so they both
+            must be of a type for which an <code><a href="#encode">ENCODE</a></code>
+            method is defined.
+          </clix:description></blockquote></p>
+      
+    
+
+    <h4 xmlns=""><a name="app-encoders">Application specific encoders</a></h4>
+
+      Suppose your application uses structs to represent its data, and
+      you want to encode such structs using JSON in order to send it
+      to a client application.  Suppose further that your structs also
+      include internal information that you do not want to send.  Here
+      is some code that illustrates how one could implement a
+      serialization function:
+
+      <pre>CL-USER> (defstruct user name age password)
+USER
+CL-USER> (defmethod json:encode ((user user) &optional (stream *standard-output*))
+           (json:with-output (stream)
+             (json:with-object ()
+               (json:encode-object-element "name" (user-name user))
+               (json:encode-object-element "age" (user-age user)))))
+#<STANDARD-METHOD YASON:ENCODE (USER) {5B40A591}>
+CL-USER> (json:encode (list (make-user :name "horst" :age 27 :password "puppy")
+                            (make-user :name "uschi" :age 28 :password "kitten")))
+[{"name":"horst","age":27},{"name":"uschi","age":28}]
+(#S(USER :NAME "horst" :AGE 27 :PASSWORD "puppy")
+ #S(USER :NAME "uschi" :AGE 28 :PASSWORD "kitten"))</pre>
+
+      As you can see, the streaming API and the DOM encoder can be
+      used together.  <code xmlns=""><a href="#encode">ENCODE</a></code> invokes itself
+      recursively, so any application defined method will be called
+      while encoding in-memory objects as appropriate.
+
+    
+  
+
+  <h3 xmlns=""><a class="none" name="index">Symbol index</a></h3>
+    <ul xmlns="">
+<li><code><a href="#*parse-json-arrays-as-vectors*">*parse-json-arrays-as-vectors*</a></code></li>
+<li><code><a href="#*parse-json-booleans-as-symbols*">*parse-json-booleans-as-symbols*</a></code></li>
+<li><code><a href="#*parse-object-key-fn*">*parse-object-key-fn*</a></code></li>
+<li><code><a href="#encode">encode</a></code></li>
+<li><code><a href="#encode-array-element">encode-array-element</a></code></li>
+<li><code><a href="#encode-object-element">encode-object-element</a></code></li>
+<li><code><a href="#no-json-output-context">no-json-output-context</a></code></li>
+<li><code><a href="#parse">parse</a></code></li>
+<li><code><a href="#with-array">with-array</a></code></li>
+<li><code><a href="#with-object">with-object</a></code></li>
+<li><code><a href="#with-object-element">with-object-element</a></code></li>
+<li><code><a href="#with-output">with-output</a></code></li>
+<li><code><a href="#with-output-to-string*">with-output-to-string*</a></code></li>
+</ul>
+  
+
+  <h3 xmlns=""><a class="none" name="license">License</a></h3>
+    <pre class="none">Copyright (c) 2008 Hans Hübner
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  - Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  - Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  - Neither the name BKNR nor the names of its contributors may be
+    used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</pre>
+  
+
+  <h3 xmlns=""><a class="none" name="ack">Acknowledgements</a></h3>
+    Thanks go to Edi Weitz for being a great inspiration.  This
+    documentation as been generated with a hacked-up version of
+    his <a href="http://weitz.de/documentation-template/">DOCUMENTATION-TEMPLATE</a>
+    software.
+  
+
+</body></html>





More information about the Bknr-cvs mailing list