]> arthur.barton.de Git - netatalk.git/commitdiff
Add Docbook documentation to tree
authorRalph Boehme <sloowfranklin@gmail.com>
Mon, 13 May 2013 08:04:44 +0000 (10:04 +0200)
committerRalph Boehme <sloowfranklin@gmail.com>
Mon, 13 May 2013 08:04:44 +0000 (10:04 +0200)
44 files changed:
configure.ac
doc/Makefile.am
doc/gfx_and_css/logo.ai [new file with mode: 0644]
doc/gfx_and_css/logo.pdf [new file with mode: 0644]
doc/gfx_and_css/logo.png [new file with mode: 0644]
doc/gfx_and_css/netatalk.css [new file with mode: 0644]
doc/html.xsl.in [new file with mode: 0644]
doc/man.xsl.in [new file with mode: 0644]
doc/manpages/man1/ad.1.xml [new file with mode: 0644]
doc/manpages/man1/afpldaptest.1.xml [new file with mode: 0644]
doc/manpages/man1/afppasswd.1.xml [new file with mode: 0644]
doc/manpages/man1/afpstats.1.xml [new file with mode: 0644]
doc/manpages/man1/apple_dump.1.xml [new file with mode: 0644]
doc/manpages/man1/asip-status.pl.1.xml [new file with mode: 0644]
doc/manpages/man1/dbd.1.xml [new file with mode: 0644]
doc/manpages/man1/macusers.1.xml [new file with mode: 0644]
doc/manpages/man1/megatron.1.xml [new file with mode: 0644]
doc/manpages/man1/netatalk-config.1.xml [new file with mode: 0644]
doc/manpages/man1/uniconv.1.xml [new file with mode: 0644]
doc/manpages/man5/afp.conf.5.xml [new file with mode: 0644]
doc/manpages/man5/afp_signature.conf.5.xml [new file with mode: 0644]
doc/manpages/man5/afp_voluuid.conf.5.xml [new file with mode: 0644]
doc/manpages/man5/extmap.conf.5.xml [new file with mode: 0644]
doc/manpages/man8/afpd.8.xml [new file with mode: 0644]
doc/manpages/man8/cnid_dbd.8.xml [new file with mode: 0644]
doc/manpages/man8/cnid_metad.8.xml [new file with mode: 0644]
doc/manpages/man8/netatalk.8.xml [new file with mode: 0644]
doc/manual/configuration.xml [new file with mode: 0644]
doc/manual/install.xml [new file with mode: 0644]
doc/manual/intro.xml [new file with mode: 0644]
doc/manual/manual.xml.in [new file with mode: 0644]
doc/manual/upgrade.xml [new file with mode: 0644]
doc/netatalk.html [new file with mode: 0644]
doc/www/ReleaseNotes [new file with mode: 0644]
doc/www/asciidoc.conf [new file with mode: 0644]
doc/www/asciidoc.py [new file with mode: 0755]
doc/www/create-relnotes.sh [new file with mode: 0755]
doc/www/html5.conf [new file with mode: 0644]
doc/www/javascripts/asciidoc.js [new file with mode: 0644]
doc/www/lang-en.conf [new file with mode: 0644]
doc/www/netatalk-relnotes.conf [new file with mode: 0644]
doc/www/stylesheets/asciidoc.css [new file with mode: 0644]
macros/netatalk.m4
man/man1/ad.1

index 566df4f4618623ab246041b84185063b6fe59ec4..fd252e6f43ce9a56c02704d7ae7c0ab6dd61059d 100644 (file)
@@ -195,6 +195,9 @@ AC_NETATALK_FHS
 dnl netatalk lockfile path, must come after AC_NETATALK_FHS
 AC_NETATALK_LOCKFILE
 
+dnl Check for Docbook and build documentation if found
+AX_CHECK_DOCBOOK
+
 CFLAGS="-I\$(top_srcdir)/include -I\$(top_builddir)/include $CFLAGS"
 UAMS_PATH="${uams_path}"
 
@@ -246,6 +249,9 @@ AC_OUTPUT([Makefile
        distrib/initscripts/Makefile
        distrib/m4/Makefile
        doc/Makefile
+    doc/html.xsl
+    doc/man.xsl
+    doc/manual/manual.xml
        etc/Makefile
        etc/afpd/Makefile
        etc/cnid_dbd/Makefile
index a6fcda87c26eefbfa516d8a595f87943f11a3cb7..d8e2be1c5d64f37faf300294d6e7e555cec3d0d1 100644 (file)
@@ -1,3 +1,67 @@
-# Makefile.am for INSTALL/
+XSLTPROC=@XSLTPROC@
+XSLTPROC_FLAGS=@XSLTPROC_FLAGS@
+XHTML_STYLESHEET=$(top_srcdir)/doc/html.xsl
+MAN_STYLESHEET=$(top_srcdir)/doc/man.xsl
 
-EXTRA_DIST = DEVELOPER
+htmldir = $(prefix)/share/doc/@PACKAGE@
+dist_html_DATA = @PACKAGE@.html
+
+XML_MANPAGES = \
+       ${top_srcdir}/doc/manpages/man1/ad.1.xml \
+       ${top_srcdir}/doc/manpages/man1/afpldaptest.1.xml \
+       ${top_srcdir}/doc/manpages/man1/afppasswd.1.xml \
+       ${top_srcdir}/doc/manpages/man1/afpstats.1.xml \
+       ${top_srcdir}/doc/manpages/man1/apple_dump.1.xml \
+       ${top_srcdir}/doc/manpages/man1/asip-status.pl.1.xml \
+       ${top_srcdir}/doc/manpages/man1/dbd.1.xml \
+       ${top_srcdir}/doc/manpages/man1/macusers.1.xml \
+       ${top_srcdir}/doc/manpages/man1/megatron.1.xml \
+       ${top_srcdir}/doc/manpages/man1/netatalk-config.1.xml \
+       ${top_srcdir}/doc/manpages/man1/uniconv.1.xml \
+       ${top_srcdir}/doc/manpages/man5/afp_signature.conf.5.xml \
+       ${top_srcdir}/doc/manpages/man5/afp_voluuid.conf.5.xml \
+       ${top_srcdir}/doc/manpages/man5/afp.conf.5.xml \
+       ${top_srcdir}/doc/manpages/man5/extmap.conf.5.xml \
+       ${top_srcdir}/doc/manpages/man8/afpd.8.xml \
+       ${top_srcdir}/doc/manpages/man8/cnid_dbd.8.xml \
+       ${top_srcdir}/doc/manpages/man8/cnid_metad.8.xml \
+       ${top_srcdir}/doc/manpages/man8/netatalk.8.xml
+
+MAN_MANPAGES = \
+       ${top_builddir}/man/man1/ad.1 \
+       ${top_builddir}/man/man1/afpldaptest.1 \
+       ${top_builddir}/man/man1/afppasswd.1 \
+       ${top_builddir}/man/man1/afpstats.1 \
+       ${top_builddir}/man/man1/apple_dump.1 \
+       ${top_builddir}/man/man1/asip-status.pl.1 \
+       ${top_builddir}/man/man1/dbd.1 \
+       ${top_builddir}/man/man1/macusers.1 \
+       ${top_builddir}/man/man1/megatron.1 \
+       ${top_builddir}/man/man1/netatalk-config.1 \
+       ${top_builddir}/man/man1/uniconv.1 \
+       ${top_builddir}/man/man5/afp_signature.conf.5 \
+       ${top_builddir}/man/man5/afp_voluuid.conf.5 \
+       ${top_builddir}/man/man5/afp.conf.5 \
+       ${top_builddir}/man/man5/extmap.conf.5 \
+       ${top_builddir}/man/man8/afpd.8 \
+       ${top_builddir}/man/man8/cnid_dbd.8 \
+       ${top_builddir}/man/man8/cnid_metad.8 \
+       ${top_builddir}/man/man8/netatalk.8
+
+if HAVE_XSLTPROC
+${top_srcdir}/man/man1/%.1.in : $(MAN_STYLESHEET) ${top_srcdir}/doc/manpages/man1/%.1.xml
+               @xsltproc -o $(top_builddir)/man/man1/ $(MAN_STYLESHEET) $<
+               @$(SED) -i -e "s@:NETATALK_VERSION:@Netatalk $(VERSION)@g" $@
+${top_srcdir}/man/man5/%.8.in : $(MAN_STYLESHEET) ${top_srcdir}/doc/manpages/man5/%.5.xml
+               @xsltproc -o $(top_builddir)/man/man5/ $(MAN_STYLESHEET) $<
+               @$(SED) -i -e "s@:NETATALK_VERSION:@Netatalk $(VERSION)@g" $@
+${top_srcdir}/man/man8/%.8.in : $(MAN_STYLESHEET) ${top_srcdir}/doc/manpages/man8/%.8.xml
+               @xsltproc -o $(top_builddir)/man/man8/ $(MAN_STYLESHEET) $<
+               @$(SED) -i -e "s@:NETATALK_VERSION:@Netatalk $(VERSION)@g" $@
+
+all-local: $(MAN_MANPAGES)
+
+endif
+
+distclean-local:
+       $(RM) -f $(top_builddir)/doc/html.xsl $(top_builddir)/doc/html.xsl $(top_builddir)/doc/manual/manual.xml
diff --git a/doc/gfx_and_css/logo.ai b/doc/gfx_and_css/logo.ai
new file mode 100644 (file)
index 0000000..0534656
--- /dev/null
@@ -0,0 +1,687 @@
+%PDF-1.5\r%âãÏÓ\r
+1 0 obj\r<</Metadata 458 0 R/Pages 2 0 R/OCProperties<</D<</RBGroups[]/ON[15 0 R 23 0 R 41 0 R 49 0 R 67 0 R 75 0 R 93 0 R 100 0 R 126 0 R 180 0 R 234 0 R 292 0 R 350 0 R 408 0 R]/OFF[119 0 R]/Order 407 0 R>>/OCGs[15 0 R 23 0 R 41 0 R 49 0 R 67 0 R 75 0 R 93 0 R 100 0 R 119 0 R 126 0 R 180 0 R 234 0 R 292 0 R 350 0 R 408 0 R]>>/Type/Catalog>>\rendobj\r458 0 obj\r<</Subtype/XML/Length 25612/Type/Metadata>>stream\r
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.1-c036 46.277092, Fri Feb 23 2007 14:16:18        ">
+   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+      <rdf:Description rdf:about=""
+            xmlns:dc="http://purl.org/dc/elements/1.1/">
+         <dc:format>application/pdf</dc:format>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xap="http://ns.adobe.com/xap/1.0/"
+            xmlns:xapGImg="http://ns.adobe.com/xap/1.0/g/img/">
+         <xap:CreatorTool>Adobe Illustrator CS3</xap:CreatorTool>
+         <xap:CreateDate>2009-06-03T14:56:54-07:00</xap:CreateDate>
+         <xap:ModifyDate>2009-06-04T10:49:53-07:00</xap:ModifyDate>
+         <xap:MetadataDate>2009-06-04T10:49:53-07:00</xap:MetadataDate>
+         <xap:Thumbnails>
+            <rdf:Alt>
+               <rdf:li rdf:parseType="Resource">
+                  <xapGImg:width>256</xapGImg:width>
+                  <xapGImg:height>256</xapGImg:height>
+                  <xapGImg:format>JPEG</xapGImg:format>
+                  <xapGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FUm8y+cvKnle1F15h1a10uEglPrMqoz06iNCebn2UHFXjHmr/nMz8u9NLxaBY3mvTLXjJQW&#xA;du3+zlDS/wDJLFXlHmH/AJzM/M2/LJpFnp+jwn7DLG1zOPm8remf+ReKvP8AV/z5/OLVSTdebNQT&#xA;l1FpILMda9LYQ4qxW98z+Zb5uV7q17dMepmuJZD0p+0x7YqlmKuxVM7LzP5lsW5WWrXtqw6GG4lj&#xA;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&#xA;REf5NWzf9LVx/wA8R/zXiqKsvyMtbi/trU6u6idbpi/oA0+rWU92Nuf7Rt+P01xVkXl7/nGOx1a/&#xA;8n2reYJYR5o0FtckcWyt6DKts3ogeoOY/wBK+1t06Yqm1j/ziPp1z581XyufMsyx6bYWd8t19UUl&#xA;zdyTIUKertx9DrXvirtf/wCcR9O0rzR5X0RfMs0q+Yri7gec2iqYRa2cl0CF9U8uRi49RirIv+hH&#xA;NK/6m6f/AKQk/wCq2Ku/6Ec0r/qbp/8ApCT/AKrYq7/oRzSv+pun/wCkJP8Aqtirv+hHNK/6m6f/&#xA;AKQk/wCq2Ku/6Ec0r/qbp/8ApCT/AKrYq7/oRzSv+pun/wCkJP8Aqtirv+hHNK/6m6f/AKQk/wCq&#xA;2Ku/6Ec0r/qbp/8ApCT/AKrYq7/oRzSv+pun/wCkJP8Aqtirv+hHNK/6m6f/AKQk/wCq2Ku/6Ec0&#xA;r/qbp/8ApCT/AKrYqyeL/nFWwSJEPmOZiqhS31Vd6Clf73FV/wD0Kxp//UxS/wDSMv8A1UxV3/Qr&#xA;Gn/9TFL/ANIy/wDVTFXyZ+alhZ6Z+YGtaTZ3RvLfTLg2S3DKELPAOEvwgtSkoYdcVeo/84Z+Xjf/&#xA;AJm3mrutYdH0+RlfwnuWWJB9MfqYq9X/AOczPKp1L8u7HX4k5TaDeD1Gp9m3vAIn/wCSqxYq+LUd&#xA;kdXU0ZSCp9xir1GyukurSG4XpKgb5EjcfQcVV8VbUVOKpP5k0xbqW3Bmkj4K32DTqR/TFUtj8sxN&#xA;/wAflwP9kP6Yqio/KMLf8f1yPk4/piqKj8kwt/0sbsfJx/TFUVH5Cgb/AKWd4Pk4/piqLi/Lm3b/&#xA;AKW18PlIP6Yqio/yxtm/6XGoD5SD+mKo3T/yntJtTtLc63qSCZbwl1lAYehp9zcCm37Rh4t/kk4q&#xA;ynyt+RFjqOp+RLdvMusQDXvLT6tI8U6hrdglofQg+H4Yv3/T2GKp5p3/ADjlp0/5la1oJ82a6kdl&#xA;pljdreLcKJ3NxLcIUduO6J6NVHucVd5n/wCcctO0/wA5eTdKXzZrsy61c3sT3EtwplgEFjLcBoTx&#xA;+EsY+Lf5JxVlX/QqWlf9Tt5k/wCkpP8AmjFXf9CpaV/1O3mT/pKT/mjFXf8AQqWlf9Tt5k/6Sk/5&#xA;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</xapGImg:image>
+               </rdf:li>
+            </rdf:Alt>
+         </xap:Thumbnails>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/">
+         <xapMM:DocumentID>uuid:1B95FEC551E111DEA13AAE68EE5F3A4D</xapMM:DocumentID>
+         <xapMM:InstanceID>uuid:58ad672b-c584-4acf-894c-9cb9832873ef</xapMM:InstanceID>
+         <xapMM:DerivedFrom rdf:parseType="Resource"/>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xapTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+            xmlns:xapG="http://ns.adobe.com/xap/1.0/g/">
+         <xapTPg:NPages>1</xapTPg:NPages>
+         <xapTPg:HasVisibleTransparency>True</xapTPg:HasVisibleTransparency>
+         <xapTPg:HasVisibleOverprint>False</xapTPg:HasVisibleOverprint>
+         <xapTPg:MaxPageSize rdf:parseType="Resource">
+            <stDim:w>3.000000</stDim:w>
+            <stDim:h>3.000000</stDim:h>
+            <stDim:unit>Inches</stDim:unit>
+         </xapTPg:MaxPageSize>
+         <xapTPg:PlateNames>
+            <rdf:Seq>
+               <rdf:li>Black</rdf:li>
+            </rdf:Seq>
+         </xapTPg:PlateNames>
+         <xapTPg:SwatchGroups>
+            <rdf:Seq>
+               <rdf:li rdf:parseType="Resource">
+                  <xapG:groupName>Default Swatch Group</xapG:groupName>
+                  <xapG:groupType>0</xapG:groupType>
+               </rdf:li>
+            </rdf:Seq>
+         </xapTPg:SwatchGroups>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
+         <illustrator:Type>Document</illustrator:Type>
+      </rdf:Description>
+   </rdf:RDF>
+</x:xmpmeta>
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                           
+<?xpacket end="w"?>\rendstream\rendobj\r2 0 obj\r<</Count 1/Type/Pages/Kids[5 0 R]>>\rendobj\r15 0 obj\r<</Intent 16 0 R/Usage 17 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r23 0 obj\r<</Intent 24 0 R/Usage 25 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r41 0 obj\r<</Intent 42 0 R/Usage 43 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r49 0 obj\r<</Intent 50 0 R/Usage 51 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r67 0 obj\r<</Intent 68 0 R/Usage 69 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r75 0 obj\r<</Intent 76 0 R/Usage 77 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r93 0 obj\r<</Intent 94 0 R/Usage 95 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r100 0 obj\r<</Intent 101 0 R/Usage 102 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r119 0 obj\r<</Intent 120 0 R/Usage 121 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r126 0 obj\r<</Intent 127 0 R/Usage 128 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r180 0 obj\r<</Intent 181 0 R/Usage 182 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r234 0 obj\r<</Intent 235 0 R/Usage 236 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r292 0 obj\r<</Intent 293 0 R/Usage 294 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r350 0 obj\r<</Intent 351 0 R/Usage 352 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r408 0 obj\r<</Intent 409 0 R/Usage 410 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r409 0 obj\r[/View/Design]\rendobj\r410 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r351 0 obj\r[/View/Design]\rendobj\r352 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r293 0 obj\r[/View/Design]\rendobj\r294 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r235 0 obj\r[/View/Design]\rendobj\r236 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r181 0 obj\r[/View/Design]\rendobj\r182 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r127 0 obj\r[/View/Design]\rendobj\r128 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r120 0 obj\r[/View/Design]\rendobj\r121 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r101 0 obj\r[/View/Design]\rendobj\r102 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r94 0 obj\r[/View/Design]\rendobj\r95 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r76 0 obj\r[/View/Design]\rendobj\r77 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r68 0 obj\r[/View/Design]\rendobj\r69 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r50 0 obj\r[/View/Design]\rendobj\r51 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r42 0 obj\r[/View/Design]\rendobj\r43 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r24 0 obj\r[/View/Design]\rendobj\r25 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r16 0 obj\r[/View/Design]\rendobj\r17 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r407 0 obj\r[408 0 R]\rendobj\r5 0 obj\r<</Parent 2 0 R/Contents 452 0 R/BleedBox[0.0 0.0 216.0 216.0]/PieceInfo<</Illustrator 401 0 R>>/ArtBox[16.0 18.25 200.0 202.25]/Group 453 0 R/MediaBox[0.0 0.0 216.0 216.0]/Thumb 457 0 R/TrimBox[0.0 0.0 216.0 216.0]/Resources<</XObject<</Fm0 425 0 R/Fm1 431 0 R/Fm2 441 0 R/Fm3 447 0 R>>/Properties<</MC0 408 0 R>>/ExtGState<</GS0 416 0 R/GS1 448 0 R>>>>/Type/Page/LastModified(D:20090604104953-07'00')>>\rendobj\r452 0 obj\r<</Length 1187/Filter/FlateDecode>>stream\r
+H\89\94WÝnå4\10¾ÏSø\ 5âzl\8f=¾¥\v\­Ð\8a\v\1e bAb\vê®\84ÄÛóÍ8q\9c\9cs\8aPÕ&ãùûæÏ\99>ýôì\9e>>\a÷Ý\87g·¼-ÁE*ö»ê\9f¯¿.¿¸?qj?¾&v\7f,O?þ\1cÜoß\967GvN\8e\828jâ%\ 5r/¯&ÿº¬Y|\8b\8ax®Í­©ùÂrÐú\14÷²\8c\ 3JÕ3\8cìº+Õê\89\9b\1aÙ__\96+óª}5\7fq?péÏËòyù´EH\88n\8aJ\92¯9EW¢\97*m\8a\8c|FÈÙÇ\88D\15H\15\10Ì\8aÀ\88â\93d\8d\8b\82o\92\1c\15Ï\ 5\0\1aÎ\9bK    T\85pó"Ñåâc5áê3Þ\98\ 4\83\81\9dàoPäÙ×\96\1dÁ^Ð\f¬)xÎÙ  \ 2VvD\1eØU\81\ e\fçäIª+ð\9a\1cpP\\8d¾Uä\8d\9b' ¬ìK\89\b\0F²Ó\æ¨Ò %²\1eD¸X\8bx
\8f0ªd*¢dJ¤â5ø\92\93\1e¨mõA¦,\ 5ÊðAµ\93Ü¥\11d\9aøÍ×Pwe!¤\8b\12\81¡\fß 9æ\81\fd\97Þ\80\93h\9h~Cð\19Y\ 3@M\1ehønÉ\95ìS5ó\14\918Õè5\     %\89\88¥©¢ÑÙ7h\10!*\1c¨
+\a3\ 2ßÅzPK\ 3\15Î\e\1d³ñ3\ f\8dTÌh\ eæ\16´\18Mb\12fAPw\19¨2Ù\ 1Ê\974\f4H«\11ó\17t.     í\9b0Cè¾M\1a)\14ív$Öø=j ñ\82aøg±£Xy\1c}±Æ\f5Ï'hF.ÓAïñµ7¹öýßÓ¤\84Ó¤DÌ\15\1aºa\ 6ÐìcL\82KäÑH_\96\82«!\r\8aì\89n?\88ÁB\a\92A_1ITíµ\987ÊãU\ f\7f7t\a&F/°ÀMds>PaD\13ra6û+&\98J\ 1\ro9Þ\90È\88\82\a\a²\1d °\9a³+ÝcI¸EøBì\81\86ãõ\1a\b\ 6\8a9ßË."\v¢Y@\91*\9aáJ\8f,¢y3_É!-z|¦î%\94P0°\1eÀHÝ­\96èJÏ~oÉ!\8d[¦Ü\90w\81dd\ 4ß\1c6ýùRÖ®\8a¸:Ìy\9cZ\ 3\83l\94>SÊ*\8d«\0Ú\98÷FZëlj\83ljk\97Fy¬\85fZÙì+wOjj\90é¬{\ 3\9f\93\ 1\7f<-ç\19èT9%íLÝMRÁ<Ãÿÿó\82ø5\14µ|ÔI\87»\1cdÖ0{/\18S\13\16ú k
+Ãa,m¥8\86ø\ 6%nh*!:»xc\9cË\89/ièÃ\16{A   ÃV¦\ 3-+ʦ\9fà\bWVU½\8b\9bCm¥ß\ eµ\f\ 2íÂCÔªF5M4:DW\bý.ÕÞ¼l\1f\91qp1ÐcÁm_ðE¦Ä&\86OKl\98<\·¢ÛÓç¥\81Ñd\bÀJÁÇt\12Ð\1ch\15\87\ 5\9fÿ\93\84í\ 2C\800Ýõ,P4{\87\ 4\93Ä\9bnm¤[ÛÓ\ f¯Á}øk\86\8eU\ 2yz\az\17x\ fú&ñ\18ú&ð\ eôMâ}èÔ¡SCw 
+X\8fZ@\11±\ 6\85\98Ô\7f¬u\ 3\8f¯"°l\12
+\9dÏ|Dß\ 6¿\ 3?ñ     K\1aíü\8e\vv¹¶³;è\99}B\1dϨ±]\90\1f£Þ$\1e¢Þø\ fQoüG¨7ö\7f N\1dõÝÕØ\16~`ÑåiZø±±´¾ðc0\81cÅB^ëAÚÓVµýDëÞ°}îº+a¿¬1Ù¿½báWf<N®Ú7öÏþ7õ}áWK\9bä«\11:7\84\r\v«\9d\90ý_Q\8c\e\8e×¾DËÄ\gÍu²©\8b((Ýò\19Ï®V}ÁÒ\16¶ç˲¹êä$~²£\17Ì÷\1fñ\8fÙ§å_\ 1\ 6\0\1dï§\\rendstream\rendobj\r453 0 obj\r<</I false/K false/CS/DeviceCMYK/S/Transparency>>\rendobj\r457 0 obj\r<</Length 209/Filter[/ASCII85Decode/FlateDecode]/BitsPerComponent 8/ColorSpace 455 0 R/Width 27/Height 27>>stream\r
+8;Wj7_%"=*$tC/]^3R!p2\5ei:.#<:*2umX&QHWQSX?kZ@O:XR!2NU",:A&.IZ])d
+4sFGTN1#]GN(;N>&A>I\_UN-X/[rs;\^P(tkhZ2Z7Hcmh,559!+mO$N-ilCO;X7ru
+%4su8Hf\-trRT+fp'uERM?YVbeK1tUK;H$F2;_7f40XmgrX\d.MSJ41ioUrN`kD>a
+XoSNdk^<4~>\rendstream\rendobj\r416 0 obj\r<</OPM 1/BM/Normal/CA 1.0/OP false/SMask/None/ca 1.0/AIS false/op false/Type/ExtGState/SA true>>\rendobj\r448 0 obj\r<</OPM 1/BM/Normal/CA 0.5/OP false/SMask/None/ca 0.5/AIS false/op false/Type/ExtGState/SA true>>\rendobj\r425 0 obj\r<</Subtype/Form/Length 129/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 414 0 R/Resources<</Shading<</Sh0 422 0 R>>/ColorSpace<</CS0 418 0 R>>/ExtGState<</GS0 416 0 R>>>>/BBox[106.997 139.145 150.43 135.867]>>stream\r
+q
+150.43 135.867 -43.433 3.278 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+43.4326172 0 0 -43.4326172 106.9970703 137.5058594 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r431 0 obj\r<</Subtype/Form/Length 129/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 428 0 R/Resources<</Shading<</Sh0 422 0 R>>/ColorSpace<</CS0 418 0 R>>/ExtGState<</GS0 416 0 R>>>>/BBox[106.997 133.854 150.43 130.576]>>stream\r
+q
+150.43 130.576 -43.433 3.278 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+43.4326172 0 0 -43.4326172 106.9970703 132.2148438 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r441 0 obj\r<</Subtype/Form/Length 126/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 434 0 R/Resources<</Shading<</Sh0 437 0 R>>/ColorSpace<</CS0 418 0 R>>/ExtGState<</GS0 416 0 R>>>>/BBox[39.6411 84.9033 88.6143 81.626]>>stream\r
+q
+39.641 84.903 48.973 -3.277 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+-48.9736328 0 0 48.9736328 88.6142578 83.2646484 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r447 0 obj\r<</Subtype/Form/Length 126/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 444 0 R/Resources<</Shading<</Sh0 437 0 R>>/ColorSpace<</CS0 418 0 R>>/ExtGState<</GS0 416 0 R>>>>/BBox[39.6411 90.1943 88.6143 86.917]>>stream\r
+q
+39.641 90.194 48.973 -3.277 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+-48.9736328 0 0 48.9736328 88.6142578 88.5556641 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r444 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r418 0 obj\r[/DeviceN[/Black]/DeviceCMYK 419 0 R 420 0 R]\rendobj\r419 0 obj\r<</Length 91/FunctionType 4/Filter/FlateDecode/Domain[0.0 1.0]/Range[0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]>>stream\r
+H\89ª6Ô3\0\ 3\ 5#\ 5C\85¢ü\9c\1c\ 5bD\f\142óRR+\102\ÉeE
\15É\19
+Å¥I\b
+ºèf (4\ 5\ 2Ë\9b\10Pi\ 2\18S!ªåÆ0\95F\ 4\8c4\82[^\90_ P\v\10`\0.§G±\rendstream\rendobj\r420 0 obj\r<</Subtype/NChannel/Process 421 0 R>>\rendobj\r421 0 obj\r<</Components[/Cyan/Magenta/Yellow/Black]/ColorSpace/DeviceCMYK>>\rendobj\r437 0 obj\r<</ColorSpace 418 0 R/AntiAlias false/Coords[0.0 0.0 1.0 0.0]/Function 438 0 R/Extend[true true]/Domain[0.0 1.0]/ShadingType 2>>\rendobj\r438 0 obj\r<</FunctionType 3/Encode[1.0 0.0 0.0 1.0]/Domain[0.0 1.0]/Functions[439 0 R 440 0 R]/Bounds[0.967026]>>\rendobj\r439 0 obj\r<</C0[0.735]/C1[0.0]/FunctionType 2/N 1.01602/Domain[0.0 1.0]>>\rendobj\r440 0 obj\r<</C0[0.735]/C1[0.735]/FunctionType 2/N 1.0/Domain[0.0 1.0]>>\rendobj\r434 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r428 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r422 0 obj\r<</ColorSpace 418 0 R/AntiAlias false/Coords[0.0 0.0 1.0 0.0]/Function 423 0 R/Extend[true true]/Domain[0.0 1.0]/ShadingType 2>>\rendobj\r423 0 obj\r<</FunctionType 3/Encode[1.0 0.0]/Domain[0.0 1.0]/Functions[424 0 R]/Bounds[]>>\rendobj\r424 0 obj\r<</C0[1.0]/C1[0.0]/FunctionType 2/N 1.01602/Domain[0.0 1.0]>>\rendobj\r414 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r455 0 obj\r[/Indexed/DeviceRGB 255 456 0 R]\rendobj\r456 0 obj\r<</Length 428/Filter[/ASCII85Decode/FlateDecode]>>stream\r
+8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
+b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
+E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
+6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
+VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
+PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
+l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>\rendstream\rendobj\r401 0 obj\r<</Private 402 0 R/LastModified(D:20090604104953-07'00')>>\rendobj\r402 0 obj\r<</RoundtripVersion 13/ContainerVersion 11/CreatorVersion 13/AIMetaData 403 0 R/AIPrivateData1 404 0 R/AIPrivateData2 405 0 R/NumBlock 2/RoundtripStreamType 1>>\rendobj\r403 0 obj\r<</Length 860>>stream\r
+%!PS-Adobe-3.0 \r%%Creator: Adobe Illustrator(R) 13.0\r%%AI8_CreatorVersion: 13.0.2\r%%For: (admin) ()\r%%Title: (Netatalk_Logo.ai)\r%%CreationDate: 6/4/09 10:49 AM\r%%BoundingBox: 1168 738 1352 923\r%%HiResBoundingBox: 1168 738.25 1352 922.25\r%%DocumentProcessColors: Black\r%AI5_FileFormat 9.0\r%AI12_BuildNumber: 434\r%AI3_ColorUsage: Color\r%AI7_ImageSettings: 0\r%%CMYKProcessColor: 1 1 1 1 ([Registration])\r%AI3_TemplateBox: 1260.5 827.5 1260.5 827.5\r%AI3_TileBox: 972 472 1548 1206\r%AI3_DocumentPreview: None\r%AI5_ArtSize: 216 216\r%AI5_RulerUnits: 0\r%AI9_ColorModel: 2\r%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0\r%AI5_TargetResolution: 800\r%AI5_NumLayers: 1\r%AI9_OpenToView: 1107 936 4.86 1509 1080 26 1 0 50 75 0 0 1 0 1 0 1\r%AI5_OpenViewLayers: 7\r%%PageOrigin:0 0\r%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9\r%AI9_Flatten: 1\r%AI12_CMSettings: 00.6\r%%EndComments\r\rendstream\rendobj\r404 0 obj\r<</Length 16856>>stream\r
+%%BoundingBox: 1168 738 1352 923\r%%HiResBoundingBox: 1168 738.25 1352 922.25\r%AI7_Thumbnail: 128 128 8\r%%BeginData: 16714 Hex Bytes\r%0000330000660000990000CC0033000033330033660033990033CC0033FF\r%0066000066330066660066990066CC0066FF009900009933009966009999\r%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66\r%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333\r%3333663333993333CC3333FF3366003366333366663366993366CC3366FF\r%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99\r%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033\r%6600666600996600CC6600FF6633006633336633666633996633CC6633FF\r%6666006666336666666666996666CC6666FF669900669933669966669999\r%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33\r%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF\r%9933009933339933669933999933CC9933FF996600996633996666996699\r%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33\r%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF\r%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399\r%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933\r%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF\r%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC\r%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699\r%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33\r%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100\r%000011111111220000002200000022222222440000004400000044444444\r%550000005500000055555555770000007700000077777777880000008800\r%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB\r%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF\r%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF\r%524C45FD35FFA87D52522727FD09F8272752527D7DA8A8FD64FFA87D2727\r%FD19F8527DA8A8FD5CFF7D52FD21F827277DA8FD56FF7D52FD28F8277DA8\r%FD50FFA852FD2DF82752A8FD4CFF7D27FD14F827F827F8272727F827F827\r%FD13F8277DFD48FF7D27FD0FF8FD04275227522752275227522752275227\r%5227522727F827FD0FF87DFD44FF7DFD0FF8FD042752FD132752FD0627FD\r%0DF8277DFD40FFA827FD0BF8272752275227522752275227522752275227\r%522752275227522752275227522752275227522727F827FD0AF827A8FD3D\r%FF52FD0CF827275227272752272727522727275227272752272727522727\r%2752272727522727275227272752FD0427FD0BF852A8FD39FF7DFD0BF827\r%275227522752275227522752275227522752275227522752275227522752\r%275227522752275227522752275227522727FD09F8277DFD36FFA852FD0A\r%F82752FD2F27522727FD0AF827FD34FF7D27FD09F8272752275227522752\r%275227522752275227522752275227522752275227522752275227522752\r%275227522752275227522752275227522727FD09F8A8FD31FF52FD0AF852\r%272727522727275227272752272727522727275227272752272727522727\r%27522727275227272752272727522727275227272752272727522727FD09\r%F87DFD2FFF27FD08F8272752275227522752275227522752275227522752\r%275227522752275227522752275227522752275227522752275227522752\r%275227522752275227522752FD09F852FD2DFF27FD08F8272752FD3E27FD\r%09F827A8FD2AFFFD09F85227522752275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%52275227522752275227522752275227522727FD07F827A8FD27FFA8FD09\r%F85227272752272727522727275227272752272727522727275227272752\r%272727522727275227272752272727522727275227272752272727522727\r%275227272752272727522727FD08F8A8FD25FFA8FD07F827275227522752\r%275227272752275227522752275227522752275227522752275227522752\r%275227522752275227522752275227522752275227522752275227522752\r%2752275227522727FD08F8A8FD23FFA8FD08F82752FD0727F8F8FD4127FD\r%08F8A8FD22FFFD07F82727522752275227522727F8272752275227522752\r%275227522752275227522752275227522752275227522752275227522752\r%27522752275227522752275227522752272727522752275227522752FD07\r%F827A8FD20FFFD07F8FD0427522727275227F8F8F8272727522727275227\r%272752272727522727275227272752272727522727275227272752272727\r%5227272752272727522727275227272752F8F8F8522727275227272752FD\r%07F827A8FD1EFF27FD06F82727522752275227522727F8F8F85227522752\r%275227522752275227522752275227522752275227522752275227522752\r%27522752275227522752275227522752275227522727F8F8F85227522752\r%27522752FD07F827FD1DFF27FD06F8FD08275227FD05F8FD3927FD04F8FD\r%082752FD07F852FD1BFF7DFD06F82727522752275227522727FD05F85227\r%522752275227522752275227522752275227522752275227522752275227\r%52275227522752275227522752275227522752275227522752FD05F82727\r%52275227522752FD07F87DFD19FF7DFD07F8275227272752FD0427FD05F8\r%272752272727522727275227272752272727522727275227272752272727\r%52272727522727275227272752272727522727275227272752FD0427FD05\r%F8272752272727522727FD07F8A8FD18FF27FD05F8272752275227522752\r%2727FD06F827522752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%522752FD07F8272752275227522727FD07F8FD17FF52FD06F82752FD0827\r%FD07F8FD3B27FD07F8FD0927FD06F827FD15FFA8FD06F827522752275227\r%522752FD07F8272752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%522752275227FD08F8522752275227522727FD06F87DFD14FFFD07F82727\r%52272727522727FD09F85227272752272727522727275227272752272727\r%522727275227272752272727522727275227272752272727522727275227\r%272752272727522727FD09F85227272752FD0427FD06F8A8FD12FF52FD06\r%F852275227522752275227FD08F827275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%5227522752275227522752275227FD0AF8522752275227522727FD05F852\r%FD11FF7DFD06F8FD0B27FD09F8FD3B27FD0BF852FD0627FD07F8A8FD10FF\r%27FD05F82727522752275227522727FD09F8272752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227FD0AF8272752275227522752\r%27FD05F827FD0FFF7DFD06F827272752272727522727FD0BF82727522727\r%275227272752272727522727275227272752272727522727275227272752\r%2727275227272752272727522727275227272752FD0427FD0BF8FD042752\r%FD0427FD06F87DFD0EFF27FD05F82752275227522752275227FD0AF82727\r%522752275227522752275227522752275227522752275227522752275227\r%52275227522752275227522752275227522752275227522752275227FD0C\r%F8522752275227522727FD05F827FD0DFF52FD06F8FD0B27FD0BF852FD3A\r%27FD0DF852FD0727FD06F87DFD0CFF27FD05F82727522752275227522752\r%FD0BF8272752275227522752275227522752275227522752275227522752\r%275227522752275227522752275227522752275227522752275227522752\r%275227FD0CF827275227522752275227FD05F827FD0BFF7DFD05F8FD0427\r%52272727522727FD0DF85227272752272727522727275227272752272727\r%522727275227272752272727522727275227272752272727522727275227\r%272752272727522727FD0DF8FD04275227272752FD06F87DFD0AFF27FD05\r%F8275227522752275227522727FD0BF82727522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%52275227522752275227522752275227FD0EF8522752275227522727FD05\r%F827FD09FF7DFD06F8FD0B27FD0DF8FD3A27FD0FF8FD0A27FD05F8A8FD08\r%FF52FD05F8272752275227522752275227FD0CF827275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%52275227522752275227522752275227522752FD0FF85227522752275227\r%5227FD05F852FD08FFFD06F82727275227272752FD0427FD0DF827275227\r%272752272727522727275227272752272727522727275227272752272727\r%5227272752272727522727275227272752272727522727FD10F827522727\r%275227272752FD06F8A8FD06FF7DFD06F85227272752272727522752FD0E\r%F8275227522727275227272752272727522727275227522752FD0B275227\r%522752275227522752275227522752275227522727FD0FF8272752275227\r%5227522727FD05F87DFD06FF52FD05F8FD05522752525227525227F827F8\r%27F827F827F827F827F827525227525252275252522752525227FD055227\r%522727FD07F827F827F8FD04275227272752FD0C27FD11F8FD0A27FD05F8\r%27FD06FFFD05F852FD29FFA87DFFFFFF7D7DFFFF27FF52A8527D527DFD0E\r%52275227522752FD0427FD11F82727522752275227522752FD05F827A8FD\r%04FF7DFD05F87DFD29FF7D7DFFFFFF7D52FFFF27FF7D7D52527D527DFD06\r%5227522752275252522752FD0627FD13F827275227272752FD0427FD05F8\r%7DFD04FF52FD05F8FD0D52FD1027FD0C522727F8272727F8272727F827F8\r%27F827F827F827F827F827F827F827F8F8F827275227522752275227FD12\r%F8272752275227522752275227FD05F852FD04FFFD05F827FD047D527D7D\r%7D52FD057DFD0F527D7D7D527D7D7D527D7D7D5252272752525227F87D52\r%2752FD0727F827F827F827F827F827F827F8FD0927FD13F852FD0A27FD05\r%F827FFFFFFA8FD05F87DFD2AFFA852FFFFFF7D7DFFFF27FF7DA8527D7D7D\r%527D527DFD0652275227522727275227522727F827F827FD0FF827275227\r%522752275227522727FD05F8A8FFFF7DFD05F87DA8FFA8A8A8FFA8A8A8FF\r%A8A8A8FFFD13A8FFA8FFFD05A8FF5252A8A8A85227FFA827A8527DFD0552\r%275227522752FD0827F827F8272727F827FD12F827522727275227272752\r%272727FD05F87DFFFF52FD04F827275227522752275227522752275227FD\r%12F827275227FD2AF827FD15F827275227522752275227522752FD05F852\r%FFFF27FD05F8FD0F27FD13F827FD42F8FD0D27FD06F8FFFFFD05F8272752\r%2752275227522752275227522727F8F8F827F8F8F827FD07F827FD07F827\r%FD08F8527D527D527D527D27FD06F827F8F8F827F8F8F827FD07F827F8F8\r%F827FD07F827FD08F82752275227522752275227522752FD05F827FFA8FD\r%06F852277DA8FFA8FF522727A8A8FFA8FF27F8F8FD08A8FF27F8FD0BA8FF\r%27FD06F8FD08FF52F8F8F8FD0CA852F8F827FFFD07A827F8F8F827FD05A8\r%7DFD05F8FD04A8FF7D2727FD04A8FF7D27FD05F8A87DFD05F82727277DFD\r%04FFA82752A8FD04FF52F827FD09FF52F8FD0CFF52FD05F87DFD08FF27F8\r%F827FD0CFF52F8F852FD08FF27F8F8F827FD05FF7DFD04F827FD06FF2752\r%FD05FF7D27FD05F87D52FD05F82727F87DFD05FF5227A8FD04FF52F8F8FD\r%09FF27F8A8FD0BFF27FD05F87DFD08FF27F8F8F8FD0CFF7DF8F852FD08FF\r%52F8F8F827A8FD04FF7DFD05F8FD05FF7D277DFD05FF2727FD05F85252FD\r%05F85227277DFD05FF7D27A8FD04FF522727FD09FF52F8FD0CFF7DFD04F8\r%27FD09FF27F8F827FD0CFF7DF8F8A8FD08FF7DF8F8F827FD05FF7DFD04F8\r%27FD05FFA827FD05FF7D272727FD04F85227FD04F8FD04277DFD05FFA827\r%A8FD04FF5227F8FD05FFA852527D27F8527D52A8FD05FF7D527D27FD04F8\r%52FD09FF27F8F8F852527DA8FD05FF7D7D5227F8F8A8FD08FFA8F8F8F827\r%FD05FF7DFD04F827FD05FF7D52FD05FF522752FD05F82727FD05F8522727\r%7DFD06FF52A8FD04FF522727A8FD04FF7DFD08F87DFD05FFFD08F87DFD09\r%FF27FD06F87DFD05FF27FD05F8FD09FFA8F8F8F827FD05FF7DFD04F852FD\r%05FFA87DFD05FF27522727FD04F827FD05F8FD04277DFD06FF52A8FD04FF\r%272727FD05FF7DFD08F8A8FD05FF27FD07F8FD05FF7DFFFFFFA827FD06F8\r%7DFD05FFFD05F827A8FFFFFFA8FD05FFF8F8F827FD05FF7DF8F8F82727FD\r%05FFA8A8FD04FF7D272727FD05F827FD06F85227277DFD06FFA8A8FD04FF\r%522752FD05FF7DFD08F8A8FD05FF27FD06F852FD04FFA8A8FD04FF27FD06\r%F8A8FD05FF27FD04F827FD05FFA8FD04FF52F8F827FD05FF7DF8F8272752\r%FD0BFF7D27522727FD0AF8272752277DFD06FFA8A8FD04FF522727FD05FF\r%A87D527DFD05F8A8FD05FF27FD06F87DFD04FF7D7DFD04FF27FD06F87DFD\r%05FF27FD04F852FD04FF7D7DFD04FF52F8F827FD05FF7DF8F8272727FD0A\r%FFA8FD0427FD0BF8275227277DFD0CFF522752FD09FF27FD04F87DFD05FF\r%27FD06F8FD05FF27A8FD04FFFD07F87DFD05FF27FD04F852FD04FF7D52FD\r%04FF7DF8F827FD05FF7DF8F8522752FD0AFF7D2727522727FD0AF8272727\r%F87DFD0CFF522727FD09FFFD05F8A8FD04FFA827FD05F827FD04FFA8F8A8\r%FFFFFFA8FD07F87DFD05FFFD05F87DFD04FF5252FD04FF7DF8F827A8FD04\r%FF7DF8FD0427FD0AFF7D27272752FD0BF8275227277DFD0CFF522752FD09\r%FF27FD04F87DFD05FF27FD05F87DFD04FF7DF8FD05FFFD07F87DFD05FF27\r%FD04F8A8FD04FF5227FD05FFF8F827FD05FF7DF827522752FD0AFFA85227\r%522727FD0AF8FD04277DFD0CFF522727FD05FFA8A87DA8FD05F8A8FD05FF\r%27FD05F8A8FD04FF2727FD04FFA8FD07F87DFD05FFFD05F8FD05FF2727FD\r%04FFA827F827FD05FF7DF8FD0427FD0BFF5227275227FD0AF8275227277D\r%FD0CFF522752FD05FFA8FD08F8A8FD05FF27FD04F827FD05FFA8A8FD05FF\r%FD07F87DFD05FF27F8F8F827FD05FF5227FD05FF27F827FD05FF7DF8F827\r%2752FD0BFF7D27522727FD0AF8FD04277DFD04FF7DFD07FF272727FD05FF\r%7DFD08F8A8FD05FF27FD04F852FD0BFFA8FD07F87DFD05FFFD04F827FD05\r%FFA8FD06FF52F827FD05FF7DF8F8F82727FD05FFA8FD05FFA8272727FD06\r%F827FD05F85227277DFD04FF7DA8FD06FF522752FD05FFA8FD08F8A8FD05\r%FF27FD04F8A8FD0CFFFD07F8A8FD05FF27F8F8F852FD0CFF52F827FD05FF\r%7DFD04F852FD05FFA8A8FD05FF52522727FD05F827FD04F8272752277DFD\r%04FF52A8FD06FF522727FD05FF7DFD08F8A8FD05FF27F8F8F827FD0CFFA8\r%FD07F87DFD05FF27F8F8F852FD0CFF7DF827FD05FF7DFD04F827FD05FF7D\r%7DFD05FF7D2727FD05F82752FD05F85227277DFD04FF5252FD06FF522727\r%FD06FF527D7D52FD04F87DFD05FF27F8F8F852FD05FF7D27A8FD04FFA8FD\r%07F87DFD05FF27F8F8F87DFD0CFFA8F8F8FD05FFA87D527DF827FD05FFA8\r%52FD05FF7D272727FD04F82727FD05F82727F87DFD04FF5227A8FD05FF52\r%27F8FD09FFA8FD04F8A8FD04FFA827F8F8F8A8FD05FF27F8A8FD04FFA8FD\r%07F87DFD05FFFD04F87DFD05FF5227A8FD05FFF827A8FFFFFFA8FD04FFF8\r%F8FD05FF7D52A8FD05FF2727FD05F8527DFD05F85227277DFD04FF7D27A8\r%FD05FF52F827FD09FFA8FD04F87DFD05FF27F8F827FD06FFF827A8FD04FF\r%A8FD07F87DFD05FF27F8F8F8FD06FF27F8A8FD05FF27F8FD09FFF8F8FD05\r%FFA827A8FD05FF7D27FD05F8527DFD05F82727277DFD04FF522752FD05FF\r%52F8F8FD09FF7DFD04F8A8FD05FF27F8F827FFA8FFA8FF7DF8F8FFFFFFA8\r%FF7DFD07F87DFD05FFFD04F8A8FD05FFF8F87DFD05FF2727FD08FFA8F8F8\r%FD05FFA8277DFD05FF7D27FD05F87DA8FD05F82727277DFD04FF7D2752FD\r%05FF52F8F8A8FD08FFA8FD04F87DFD05FF27FD04F827F827FD05F827F827\r%F827FD07F87DFD05FF27F8F827FD05FFA8F8F87DFD05FF52F8FD09FFF827\r%A8FD04FFA8277DFD05FFA827FD05F8A8A8FD06F852272727522752FD0527\r%52275227FD55F82752275227272752275227522727FD05F8FFFF27FD04F8\r%2727522752275227522752275227522727FD55F827275227272752272727\r%522727FD05F827FFFF52FD05F8FD04275227272752272727522727FD0DF8\r%27F8F8F827F8F8F827F8F8F827F8F8F827F827F82727F8F8272727F82727\r%27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8\r%272727F8272727F8272727F82727FD0C52FD05F827FFFF7DFD05F8275227\r%5227522752275227522752FD07275227522752275227FD08527D527D527D\r%5252527DA852FFFF52A8FFFFFF52A8FD38FFA8FD05F87DFFFFA8FD05F8FD\r%0E2752FD0B2752275227FD0C527D527D52FF52FFFF52A8FFFFFF27FD39FF\r%52FD05F8A8FFFFFF27FD05F8522752275227522752275227522727F827F8\r%27F827F827F827F827F827F827F827F827F827F827F827F827F8FD0527F8\r%FD3227FD04527D5252527D52525227FD05F8FD04FF27FD05F82752272727\r%5227272752FD0427F8F8F827F8F8F827F827F827F827F827F827F827F827\r%F827F827F827F827F852F852272727522752F82727522752275227522752\r%275227522752275227522752275227522752275227522752275227522752\r%27522752527D527D527D527D527D5252FD05F852FD04FF7DFD05F8272752\r%27522752275227522752FD05275227522752275227FD08527D527D527D52\r%FD057DA87DFFFF52A8FFFFFF52FD38FF7DFD05F87DFD04FFA8FD06F8FD0A\r%27522727F8FD0C275227522752275227FD08527D52A827FFFF527DFFA8FF\r%27A8FFFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF\r%A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFFF52FD05\r%F8A8FD05FF27FD05F827522752275227522752275227FD04F827F8F8F827\r%F8F8F827F8F8F827F8F8F827F8F8F827F8F8F827F8F8F827F827F827F827\r%F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827\r%F827F827F827F827F827F827F827F827F82727522752275227522752FD05\r%F852FD06FF7DFD05F827275227272752272727522727FD57F8FD0927FD06\r%F87DFD06FFA827FD05F8522752275227522752275227FD56F82727522752\r%2752275227FD06F8FD08FF27FD05F8FD0C27FD56F82752FD0827FD05F852\r%FD08FFA8FD05F827275227522752275227522727FD55F852275227522752\r%2752FD06F8A8FD09FF27FD05F82727522727275227272752FD56F8275227\r%272752272727FD05F827FD0AFF7DFD06F85227522752275227522727FD55\r%F8522752275227522727FD05F8A8FD0BFFFD06F8FD0727522727FD55F8FD\r%0927FD05F827A8FD0BFF7DFD05F82727522752275227FD58F82727522752\r%2752FD06F87DFD0DFF27FD05F82727522727FD5DF8272727FD07F8FD0EFF\r%7DFD06F8522752FD67F87DFD0FFF27FD06F827FD67F827FD10FFA8FD6EF8\r%A8FD11FF52FD6CF852FD12FFA827FD6BF8FD14FF7DFD6AF87DFD15FF52FD\r%68F852FD17FFFD67F827A8FD17FFA8FD66F87DFD19FF7DFD64F852FD1BFF\r%52FD62F852FD1DFF27FD60F827FD1FFF27FD07F852275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%5227522752275227522727FD07F8FD20FFA8FD08F8FD4F27FD07F8A8FD21\r%FFA827FD07F8522752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%5227522752275227522752275227522752275227522727FD07F8FD24FF7D\r%FD08F8FD0427522727275227272752272727522727275227272752272727\r%522727275227272752272727522727275227272752272727522727275227\r%27275227272752272727522727275227FD08F8A8FD25FFA827FD07F82727\r%522752275227522752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%52275227522752275227FD08F8FD28FFA827FD07F8FD4527FD09F8A8FD2A\r%FF27FD07F827275227522752275227522752275227522752275227522752\r%275227522752275227522752275227522752275227522752275227522752\r%275227522752275227522727FD08F827FD2DFF52FD09F8FD042752272727\r%522727275227272752272727522727275227272752272727522727275227\r%27275227272752272727522727275227272752272727522727FD08F827FD\r%2FFF7DFD09F8272752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227522752275227522752275227\r%52275227522727FD08F87DFD31FFA8FD0AF8FD3827FD0AF87DFD34FF52FD\r%0AF827275227522752275227522752275227522752275227522752275227\r%52275227522752275227522752275227522752275227522727FD09F852FD\r%37FF7DFD0AF8FD0427522727275227272752272727522727275227272752\r%2727275227272752272727522727275227272752FD0427FD0BF87DFD3AFF\r%52FD0BF82727522752275227522752275227522752275227522752275227\r%522752275227522752275227522752275227FD0BF852FD3DFFA827FD0CF8\r%FD042752FD2027FD0DF8277DFD40FF7D27FD0DF827275227522752275227\r%52275227522752275227522752275227522752FD0427FD0CF8277DFD44FF\r%7DFD11F8FD042752272727522727275227522752FD0627FD0FF82752FD48\r%FF7D27FD11F827F8FD0B27F827FD12F827A8FD4CFFA827FD2EF8527DFD50\r%FFA87D2727FD27F8527DFD56FFA87D2727FD21F8527DFD5DFFA87D522727\r%FD17F827527DA8FD64FFA8A87D522727FD0BF8272752527D7DFD34FFFF\r%%EndData\r\rendstream\rendobj\r405 0 obj\r<</Length 23765>>stream\r
+%AI12_CompressedDatax\9cì}i_úÈÒèý\ 2|\aP\91\1d\92\10\12\82\8a\10   ¢¸áΦ"«\ 1fÎÿyñ|ö[ÝÙC\12Ârî\9cçÞû\9b\19G;\9dªêêªêªê®´ßWoÄòÝI»\17KÆ     ¯Çï/\88½Ö|"f¼¸Õ{6\1c.fs\115\ 5oB^\12zA§üYú]îxß\13gýÉ8\83\1fÅ)x( ·\83­î¨?\ ey\83!h¹íÏ\87=h»ìÍ[óÖpð^\9b|Mâ­~HÁ\a\0\8a­9ta\12t\82à¼$\91¡9oþ\ 2\9eó\93ŸÛ\1f\7fñ\93\7f\ 1\ e\92I{Ùd\1a\90¥(/G%¡C¥\7fÓ\9b\8aS)¥#\ 5¿Cß⤳\18õÆóº8éôf³Âd8\11g\19/?lu\ 6\1e\18Uê]è\ f{0\80QkîåÐPóg$õÎ/úÃîåbÔîÁÈè$\8d\9a\93ïøí»Yë\vèÆ¿£föýl\ 4-\8dÞ|\ eä\0lÄ®ÂE³ªG      $Êÿ\ 4\9foz_}Ì`àÁkH\82\eM\87À\ fi4\14CÄSÞ4ÅÂOý\1fr_ \18÷ãXÊKÃ\7fd\8a\ 6þP\ 4#=×\86Üû«ßû;ã½\9c\8c{ÒXóâ¼Ñÿ/ \9e"\19ô\9fÔz³\18öÄ»q\7f.\11\9f?ã¤\91^Lº½!ôUß\15\86-<@ü\ f©ý\94:ܶįÞ\1c¦f2\̱\80¤     ù\11p²ÖúÓC\9c'%\ 4WÓÞøvr\8fé#I\82õrIÆKÇÓ\f\8c\ 6\8bC\9aðR\f\ 6\9f"¼lJE\86ÿ\93 "\18\b\82\ 2\9a\ 5Æ×a*®ÄþW\7f\9c\91    cßËb¿«M\ f0,-ýÀ´ÇÓºÿ8å?\89H\18ï|Þ\eËD\83X\14.tÓLÄ\81\7fþÒ¸[\98\8c\10¿gHvanÇ0ñÃÉ\97ôLý\1d?\81·\17S\89xü÷;LM]ì\8f\11HÏ%~\92\ f\17ð¨,N\16Ó³ñçÄ\13\94ô²Þ\9a\7f\83ÜöÆÝ\19(\99Ô&ýé\95Þ\80ÖZÿ¯\9eÔ\ 6º6\r9»\15[\1d@ë½jÿô:sxYnÐ~k,úóÞj@\8d\ eâ\92èåÅÅìÛ{;\99\f\8c\8fT2åfÜ\8aúÿgà¨ã\17ÆWc\89ÓË\98ä\ efL \18ÿqX ·=\ 6\9f\f½Ð\1a\ eû_bkúÝïX!°x®b\92\9e­\81\fT\ìiïã?\95ÿ»\10Ë?£ödØ\9f\8d4iÔµÔ[â¼ß\19ö\1a\7ffóÞh5´bï\13Ö!\1dÛpkiüWo8\99ê\88T[Zã®÷¡%N\9d@£iúì\8f» !X\9f56NFS´\86z\eß­i\ f\93;ÿ\16\86\v1\1e¶Æ-Ñ\8bÛU\90Èü\80ü\82=3\9a$©M\ 5\9az\aè7}±\98\87òòc\9da,\8b­n\1fl*¸\10wãqkÔëz¿ä&XéB\1eËV0ç\0¦ëyö\1c{\ 4A(    E¡ ðB^à\84´À
+\8c\90\12h!)P\ 2)\10%¡T*\15K\85\12\97¸RºÄ\96\98RªD\97\92%ªD\96\88¢P,\15\8bÅB\91\8b\1í)²E¦\98*ÒÅd\91*\92E¢ \14J\85b¡Pà\vù\ 2WH\17Ø\ 2SH\15èB²@\15È\ 2Á\v|\89\ 5\9eçó<ǧy\96\14OóI\9eâI\9eðä\85|)_Ì\17ò|>\9fçòé<\9bgò©<\9dOæ©<\99'8\81+qE®Àñ\\9eã¸4Çr\f\97âh.ÉQ\1cÉ\11i!]J\17Ó\854\9fΧ¹tÚ\93\1f&\9dJÓéd\9aJ\93i\82\15Ø\12[d\v,ÏæY\ e\1e³,æX\9a\14\ 4#0%¦È\14\18\9eÉ3\1c\93fX\86aR\fÍ$\19\8a!=\f\91\12R¥T1UHñ©|\8aK¥Sl\8aI¥Rt
+|¬\14,Ô´@\97è"] y:Ost\9afi\86NÑ4xLI\9a¢I\9aH
+ÉR²\98,$ùdÞ\93ä\92é$\9bd\92)x\9eLRI2IP\ 2\8aT\81â©<ÅQàçP\f\95¢h*IQ\1485¤@Â|\90E²@òd\9eäÈ4É\92\f\99"i2é!)\12\9c\a\ 2¦\93\80\19!x\ 2Ø\ 6\9e\ 3\vÿ\0ñ\ 4 '\0\ 2x!Y\ fáõ¿ó"È\ 6\14Ð\8aZ\1a\1eÿ»®\85\9fy\90W@sq:E0^µ\8b±\11zñEU\92\15Yu)¾´\95ôÒÿ/\v/\88¯'\9dþ÷
+ïzâK\e\ 4&N1)ID8&Î\12ɤ*8ËOv$@\16\8e¡\95Õt|\81\93\9e \9f\7fþgØ\9by\12Õñäï1þÃ\9bñ\ 4\9fa½i-\86ó×\907q      âè\8dz\12\8d>Ä!=¥\vá½ò\10²»?\80ßn<\8aë_õ(\ 1\0á}ü\ 3\7f\9cÃ/?Ðô·\97ö^x\9f_        o\17Z\1fo<(æyìz\12Ò²päñ&\0\1f\13\b#ÒÈ[9Æzk\bÞw\ f\13Qo{ì"*DÒ̳\14gÕ;\9e:¯"Q`­ÃÁ\1a\80Ó³mi\f¸Ã&SE\12Ò#É{@`þ\97Ü\f\80L\8d6ÀeZ\95à\ f\82ë\16\88]Bù\ef\13ýÕï n´Ä?Òß\8f\17µK\bò,\1f\1ey\83ÿ\1a\rÇð8\ 6\1e©Øo/æ=\88<¢¨k^\14[ÿg@ì\0¾®Wç\eÂz±7\96úPÞÄ\19pF}\8a~Ìÿ _\b=\r\1e\8e\7fµÄÙ\11èG\ 3 C¬dèúWk¸Pú¢ö\99M?dê¥n2%3Ã_ÿC¹Óîãô\vé\829ÀD\b|/1\eVsHß;úÏ\8eq<\19Û\91¬\1fßpÒ\19ôºnƦôÜÑôo9zÒqô®æµßj\ f{n\ 4\7fåLþORôÌ_®U\1d\87¥\18\r¯³\98Í'£\7fÖ\92ýûä03k!·\ 5­y`:Ü\8aã¿]/\80\96ÿ RþoÐÒÙçßÿÁ«ñ?¬\ 6³a¿ó?Ý\16Ç\18. |¸éµ\86\ eÓëjjÿi»+oG­\18Ë\1f7cùóO\8f\85d\92é䪡üÝïοÝ\fGîø\ f\ f)M¯\1aÐw¯ÿõíÆ\84«=ÿá!y\13üdâ0 öd\ e^@­÷9\97¶ÈÜ\f\9dÿ\80\15\1f\9bºÆd!vzx\1fø\1f_òaaú§I\18õæ­.x@ÛÒÁmIÇ~WN9¸\91.]g\83\ 4£Ü\87÷SÚ~í\89ÞÉb>ì\8f{ÞÙ\\9c\f\14AcS2¥¦Îbk6ï\89±¿z\9dùDô¶[ÃÖ¸cÖ\10Ó+\9da\7fêíL\90\13ù/¯Øû\ 2\8d\95\91\10+(\9a÷þµ\82ö©Ø\9bõÄ¿zÞÉ_=q\8ar6\16 I¯Â\bo\7f6A'\ 1¼m´\8f\8b÷c1ô\14¡\98«ü\19ç½è;½7x ýÿÂ\19.¯¶ñî\b~0\86\18\14¨÷~I[7¨+J·§UfrÞ\968oOZb\17X2\ 4\16\129hM\12\ 6\16ó)\80r&\84\92){è$PÒë¹íÛV\ 5meW\95hJ×k.¶Æ³i\v¤½ó\a\10÷»ÞYÿ¿z.Ù !_ÙU7&Ò0\11uE\1cnAr¼¥n\7fÞj÷\87ýù\1f\14\99&½jò\ e\9f\eðÖZã¯Eë«ç­O¦ÊÔ\ 5\9f/zÝþb¤ã:ÊçÞ\8dû\1dÐ5Eÿ¬       ª\84b\92æ^]ÊÅ´j%\19eÒ§­n×$^£Öl`\1aèl:\99\9b\86}Em\95éèNûq\99\9br\v0OTMCþÌ\9b_Ì'ªpõ\96Ä\9aóN[S \7fÖ\1f-\86-MàHÛ\891òx\90?«·D\18\9f\95\1e:­ñÙ\1föª½?¦\11\19º¢\9dS`ÙLC¨i\85¡ccÑ\ 6Æ
+\13\e
+¸õ¢\80@CO+\890t}øîw¾ÍÔ\1e!":\13±Ûë.O£7q9\99\e\1e\93zN\8e'\9a}òöÇØ\18Nfx¿ØAÌtòEyaÂ\1cdJ¯\ 5¸o\ 1ÙÜ\82lsoô6WoØqWI\ 4\12÷\92\r\16]o\17¥ÞÊv
\1e\97\f¥É"\19¬\98ôR\r\19stt\ 1½\84UÓü\92Q\8d\86Ã\b\96û^ÉëEC¿\82­æªô²\ 3[õ¼\92:»f\96Ô}]nIo­f×
+á3ì>\99¬UBs)\13 ¶Ã\1e\ 6d\10%<d}¿Ù|\18ïJ\10±\f÷d]\ f:\83G¯Éý5¿ÄÍ;Óî\b\1e\ fÇ®\89\9av]\ 3\97\92\edZa¿¾ãt*Æûèàa|\b¾¹»\9eó\89²às´sOQ\8b\14åÜW\8a\10TcµÜµ\83úþ=ùü\9cõ櫺}\9bº-ñôgÒ\ 6\9eÎú_ã\96Á×±ì\88§¶-G\b+;bkê¢_kÖîÏG­©sW©\8f¸ì\95-õî\fÅxg2\ 6ó;G+§\ 3©¨§j¦Ûè\f«C_±\e\9f\88HµW0
+uü\ 4Sö=\11ÿ˸\1e\9b\15A\ fËb\12\11V pØ\9aÆ¿]öûË\9e¶é×h\10\87\90\ 1\9cawú\83_\90\14H\9bM7ïÀ\94ÍÑ¡e\99\16]êf©+¨4²åº4\86-éSP\90þøs²¢\9b¨Ûª^Ñ\15û1í\968s`.î\b,ëuA\9btöÁEgÕD¸è«3\12.zëÍ\ 4cÛ}Ô\12\a3#Õ.:«T»è«£ÚEo\93q[\9a\93Ïñ<Þ\1dNÅÏÉØIq§³xÇì5Úô\ 3ë\87\82Ç1tÕ­¿K=ÿ5\8d\8b\82×w«\9e_nÌ\10ô\93­\90!¨uè'\85ãö\10Å®83j/iÅqÜM    \98g3{Ì\9dQ\\89¦;£?N¶Oë8\99\7f÷D\a\86Ã\9a#\99\v{´¨\8f¼\8cËrCÚ.\89:£Àr¶½ôù 8B`MºÞö\1foQìÿ\85¨u´Vð¾æv8,¸\ 6ód·Üö\f:¼ÌHÔ ÇÌ®,)Z÷\f´Y®`ÈsZµ4\88\97\ fèó×R\0fî5ë´\86=\ 5ÖÊ~\ eK\91Ôi:ìüq\10Pܧ3\9e\14úÌ!¾S2;¶\96~\86\8e\14­è\83­ëª\15CT¬£\15É\92\ 13L\89e\9f\19IJò¨\92Ö\86kØû«7tТ\19¸D(\1cp´~ãÞ\17¬\82\7f9\8d\e\99RpÖÆÎ}\86d\aÇÒK1\8cÙÜ~·º=±7s°OSÉ:i¶\89µr\90À,\9as\8d\96¦\13<-G\e<\99v\1cÜ\ 5Üaæ0tÜ¡»X';dzÝY\81%c½\18w\\19\ 4Ü»5\1e+ù -¸]êµÊ
+\83Mפ4x\17oĽ\ f½6Äß­9\18Ï\97`ãáªþ\12òþE­\b(ÑÒ óô)kT($ì+ié#5w\87²#y¥£\17\85¸\9b¥í\bÛ\ 4ÁíÒÚ«u1%\90\97R*\96I\ 6®\97\86iE¬n=i8\1c\82aÁâðå ò¨ÛlÐ\9fB´2vX±Q7\11\f\888ë!Ä\ e+6ê\89²\ 2­yÏjvÎ'mT§ \9b\e\1d\1f¥ñ\9bظ2S¡«\88ôî6k\81è®\17\85w%)¬Ã\84\0·Ð\9aJùá~ÏÉãW\0ñh=¸q^Ó\95¾Bk6\a\rB\15t\8e\14R¨s±7\ 3rp\80R\9f\fû\9d?n\89¹uZ|\94\9ee\94Ü\82    ½ý^\8cÚãV\7f¨¸\e·ßÀ\18/*Ñ\ 17Î+;aÞ\99\\84çýû»7öÎZ\7f¡  h\8dõ¥«^¤áÞÖ\f\15+EAÝ\ 5\89{ïf\18$ü4\ 2û3Yx§ ªÞÉØÛ\93¦\0£\96À}µúc\94\1dÕ!\8az\ 1\99úê\18\9dO\10\88NÏÛÇ©Ô\96wØú\83v\ZÓ)pNÚ$\99-:ß\88¼³q\11'340\12¶10u\ 1ÔM>5ôý\99w1\1e 3ÜqgñÓMZGìO\9dÝ~¥3p\ 4kЭÎ7q\9a3U\8d\H\9aäÛßêö^V¿\84KPy5Ð¥R\8c\93\0\89­?¨.¶¡ß'°\1d*\102\9dêü¦\15"\Ó\12l\96¡\98ÒYK÷ãl¿½³¤\rÑ6ÛoÕýVì\8f.P`ºZ]\eóÖ¸Û\12ÝåL\94\97ä\ 3ó\7f.\1d\1d\80\95\e¡«\19Êë\82jçyÅBàjbe;\8a\88I·ÚÉ1×Ê¢X8wF[Ù\ 6Ê\8b\ eÁ²^@\8b ¹ÒIÅj\7f¼ÞÔH\e­\85ɸÛ_©Í\12'`e>Ó\12O6é,³d=èÂAç¡Ã´X\rÇ\89$\10/\9dô®ÒfÝ&\9b\ 6Þ\89&IUû\8a\93a\9d5Q:_LÆ\93η8\19õ´Q\98w0,½|÷g\r,\93KªñÄYn\ 1\b\0éù{"\ et6&e£@®vý\9d\8c\ 2\9eµ\ 2NÝÌLë8m\999ÒsKã\13þÜA¾=ùËYGÜ\9d¯X©üÖràH®Q×\96\8e#¬5/:_\8a¢l\ 4ÂJ%\2I§ÜðXúN\ 5\91\ 5ÒÏ\8f3nã\80]¢68\9eù\8e8i·æÒ\97\146°LKÄo\1a\7f\9a\\ 6x.myj0×\9b¿Uî'%q\ 1Ó}6î\80[gÒ\f\17Òmy:i3Ã~Ö\ 56ö?ûJ\0´jIÑiÇõ¢¥¹\11\ e×gv\9cðZÙNw&Ú¬Ð\ 6\92iW(-ÍÁz"¡÷>\9c\r\89I§ÍL\82À\13zIòYP#>9¨äûJ@\99o\14ÎÎÒ©b\ fÉ\ 2zH\9f^\1d>G\8e\1fN\ 2G­Çèyòð*ÆçÄòè;ó5ö\9d\v¾h0Pè·â³\ 3æ®Rbö3¹»rö\82>ÍÔ^\ 2\179qÑa\85\12u\91ö\934½O\10³âOñ+J\1cä\8eÞâáÜqt:ËͪTÂãÏ\1dÕ|¢Òé|Î\7fU®k¹cº×(ôO²\9db<\1eøZBUë6\ 1\1f[\14ü\19ö©</þ¼òôS,\9a\1fMj³üYcþ\1dÉ2û\v¡H\1f<ð?ÃÀ\83Ç_ü$ÎÛ\96À\ e\93½¿~~Éß\16â÷öHõý2¯¹ã\81ð\9aËÌâ£H1ê_\bÁr÷ÓãÇÌ\12>@[\8a\9f¯\ f,?Ì\r\1f3\9fü÷¼ðÍ>\91\ 6v|\1c\16;dí7w|\1ax\90à\0ɳÂÛ×Û\ 4~;ü-\9euÏ||,ýs\90oÄöÇ\12\r\8f­îÂãç~\82\91\93º\ e\16¾é÷£ã¼?y\18á/£\1f\91\!p'\14z\8bpöþ|ÿû¨Ói\rÐoýHé³ö-a&\89D\8b\15û\a\1f\99þÛy\97\1fúO\ 311ò²È×\1a\87¿\88þPîèü;éñ3G÷¯¹ü¸\13\18EN.\8e\12ìèå¤Ï²\89Ùg2/vÎÈÈ Cª\10;ÅóÙ=°\8d\rôØ\87$ÑÍô\v\89\16Ì/yq\12\8cE{ü\90­\8f¤\114kþ\áìxÿ¡\14åR3\98\97³gf?Ë\16&o\91ãûîs\86jï¿b°Ù±\1f\ 6\94eÂûhJ\9e\99\aæz\8cø\94å\a!&&\8bæ}·F\90¯û\17ÅDëøPðE\9eD\84\85A\ fÞ0\14ÜÅã'Ú{g4þ=\92\15\8eåß\8e\1fJU©{!Zú\90\80QMê\f\91\88d³¥(U<ý:\91á<\9c\1c\1fu\7f.ßðLª\ 4\ 3¼+>%c\81Nü¹JÀ«F\0\19<¹A\9dz4nKùøâ;f5øò§4óÄütò·Å\9fHñ3Qý-µZ\81\ 3\9eiß]suÿã]þªÀ×\8b\9f\8dþoî÷5óåñótóö]bæ\13Ó}*½\93\91{\9e~Ì_  Å\9f\87÷Bÿ\87I\1c}\8eü_Bá3L\ 2\ 3³\1f,{Ó\9dhøÒ\8dßQ5\7fU\vW\85b¨[\95x£0Z\92}\98ýù4~\1d9½oýJ\ 3Ê2éVîèv¾\97¿=\9f/\96\87fâ¬\8e\ fÊD<\8a>\ 5T\ 34çª0÷øKO]ÿ\17õq|Z$\84\97\\12\8bÀñDZP\ 4é\bG#ü\84{3Ï\95\91³ú\89U&B\92\9cÓïÙ\ 2s      Æ¢çÓy­\9c\7f?'±Ä\1cG¦G\1fBð³\1aÏ\13Ç·OTèàíX"ÄÈ\ efqÃõ\84àá4Tøfn\ 6¥H-.h\92
+
\9c \vÓ(u\91\84æ@©F\870´ýPáë»4c\8f:w7yö\89z0ÏA½2¼7ÀÞ+\97bÑ6g5%Ü W-xüùÛ\8bn\ 4,L\96+òµæÀ\8aZÜSׯÜd?AiJ\14A\95é\8b\99×\85P}x$\14SOT$[þ\88yüÚ¸`T\9dO¡TL±<\13»ºÇ\ 6'NVî£\18i1ñ1\ró?óî\88\1f\8eï'ùÛïÇ\ 3\0Q\8d¨\0¦¥èä\92\12\ ecìsþæó;\0¯½\1eòL¤ö-YËPñ3Pa\80ÚÉ·d\ 5\8f\15Å\84\ 3\82êëmRÈ}\9d<"\ 3ÿQlÓß\ fù;\7fgfìw\98¿¹}\1e¦\7f\86±clÑ´\85\0°hÏ'çÄ1?\bNûÂq\99\fêlûÓM¸¥ç ¬%:cM\12íE)xòû ­4¦§ ÉÁ9û\ 5äõ\1aKÏÓ\1f\91£³Ù'XìÎ~\8a'\17Ãç|ãã¼ ?åò\1f¹ãJ!\ e]>îÁ
\ eyòiñ\9eo,nií)î\fv\f\1aF9±\939\94fK¯\9f\89æñéUa̲ÕÖ>q>\7fÎ\11Õà¨\ 4?º<Q%»yé·óæ    \a¿=f¡­\95Ó·\91_<~\ 3°è{¶ä\17«Á¯\82òâ\ fü\16âêÒ;òÛ
+\ 2      \8e\ 4l*@¿Ó\eøí§(u\91;O%,*y¨\93\1e\ eÆ2*\9a\88Wß8\1ft\8b25\12I\888\f\ 5h@X¤ab\88\88¨\10ß\90Úd`xT\18\vzÛÌ"\95d3ÒÚ±Ì\9b\10úl\ 6üþ|ª{û|~u\f\9dîNáÇs^ÏJ\8c\96S¸x|­c\81ÄϧÀ¥\ 2å-¯q\16°\18'Êzj×\9d\bÓ4¨X(_Ya\16\10*w\7fÎ*|2°Cê§ý)É\v\96\1c\84y\99\ 6\9b±¸\99\12<\ 2é7\ 5¢üÔð'\12\v4/6\82á \16\9a~T\9a¨,3\v?@X¬\98%\8d\15sBa\87n̨³%S±lèÆ,3På\98yÔð\8e\8cO\ 5a¤F§¤Òp\9f³\ 6¤\b\9e\84ô1\8bõE\9b-ã¬J¼C\10¥îÀ     +U\91\15\12½\86\14@/¤\18Õ\8f4/èùº¬^)/\98å\8fÒÐ4\19S'^{GRïÂFb\88§D\1e\18Öd\84;Ä\)¿á\ 1¡aH#\r¼\18]¿pþö¾:\16r\81Þ-xú\9f\94~ÁàòcX+¿jÂÇE3#øÂqXÅ\88^;\93VVûØ\ 1x.ÅAîaÿî«Ð\7f\95:\83ßCi)Ó¹\13©yÝ>\9cÑ»\1d\91\a\1cÎ@,f\fh0¡Å¯XèTrýêg¡\17m\8d3D[Ä~î>\10ä
\8b\9b§bµúËë\aÄ¿÷ò7ãâU®ñ&¶Á\83\1dæF¤\11K\ 4Ç\ e\99Kbø~\1cû\10&æ§\89½Ð3\ 4¡÷ÓR'z\9bà\99(\15ÓÅ\8d$ßþ*öÂ¥\8aæ[!Oé|Ái\8c\91½°\97ô\95.tÓ;\11\10\9a¢Ø\96\e
+\93OÉ=[\ 2ðHÃk±Iââæ%\8fè\ 2O   ¼õÔÓ6Á\89\8bÐ\ 4yJ[\ 6'.B\13ÙëS%4\86\86&\85Ì\86Ø÷m E(éa\¬Èspç\1fÈþÑã9\8fÝX\8dO\1a¨ÿ»"\v\1cH+ñTå¥Xå\99\0 \bµùëÜs\98¿ö¿Î±;L\9c\97\82OúX\ 4\8b}\96©Æ\8bg?lKc\eD\16\88q2ûóã
+{?¬Ýæ¯îª î \9d\92pj\84Ø\ 5\15\12\f\13V\15 Ì\ f\99¯gìý{ü\9aÿ¿LhïªX\1eø{ ^×Ç(©Ñ\81ߢóòt¯Íq\91#úÒ\b¶f\13¤\1c\a$\vSÎ7\86¹\b¼ýõKvnN¯¨Ü\9d\8f\93#ÕÛp\ f\985 W\ 4ýÔÓ`¿ðýâË\0ÁïïÊì¿Æa¸qÐ}~p\11\81@¤þI«
+\92A\81Á\e? N|Ú\ 3\89Lw4$Ð4\9d\ebd\86\17\8eK/q\15
++¼½\86÷\85Òx\ 1ZIù¹QZ\92¬èAâ9Ívjçüu=W§BÍÑ¥Lè¢éÏ__6îQ¬­<xøIÊ<\9e\1c\12ì`Ñ®\13µi|X\9e]õD\13fY+M¸w\8dÙãWERÈ\89â÷\1d\9d¹x8Å\b\8e\88Ó£\ f\14Ý\15\88O®p¦\83}5å+<½à      2z7ó\19æàù-Ï\1dUcê\83[ú7ÞÏãX¬\14Í\89\15!\1c\8aÒ`®\1e ¾\89vÇ°:Ý\bÂ{È÷\8dF\9aÌ\1d·ßƹ\87ëÈaæ;ÒèÃâÇý`9×Yç¥\ 4F%V<\17Ã\1f\92\8c-K\8c¯\94\95zªúk\0æN{)&\7f\88W@\94\87Y¥¿I-é謽:B\90öB(8ù,ôg}\ 6e\15bÏà?\94~\v&\88.¢|\1dØk\1f¬Ü\8aö&Ér¡:Ä]2dÚw     º\1fjÖçùj\93ìJÓxR½ì\16»#.ª\b_p\ fâôS¢X¨ìK\8bQlâËÆ¥D\80\94={8Iez\1f\87=\99O\95z\82\1fÆoH\0Ú\18c·Ãã\970^Þ¥_Kïoþg þË\97ûåß\82ê\8aõ­Ê\1dX]æÀ\ f\9càÎÐ\9aóUj'\9eúF\1f\ 6[ìg\1c»Ëëuí\v<%öábÚ0®ÝROö8Yê\95Þ®Úïà\9b\1c!\83ó\19*u"ÄK\9e\ er×`þ\1eÒ\92/ £Oîç\8e\ e\8bg£þ3\9fº\7f\8cç¯Ãõ¯üÍmD\0\97_Y~@vE½«"-('\89âÙs-\8c\9c\8d\eÜ\ 5¬óqÃ\8aøôíáACxß?l\16?\81_ü0}\10-\9e\aCAìܨº\8f=\89/ÿ\0d\82Û;ú<h|[ ¥a\11½\99\95"aæS¿¼¡¹\9a¾óo¹û\83ù\Å\\83)þò1ó\9a\0\11\1f\9fº\8dÇ\f\8f\ 2>âì¹|,\83P×W\9c¡½øùüÌô\ 3×\17àÒEóB±Y [\rÍÐ/\15ñø\8f^'Ï/N\9dîÃìeçèÊÔå¨÷\16\1aà<Zæòë¨_\8aN\9e\8c)2ßH  ¯åÑ<\1c@ý~\14\v³$Eû3XK.¾%Gæ\94y,\17.\v÷§&Ù\90w/Dß3¸Í¿70ɹ_\9dw(\83"âÀÞ\87©Ç\8f7@,æ \ eúYe\98\13á·r\\1cÖR\9a\13,OâÛ¾¯øÙø\98\14ú{\a)\10lú*?Î\9eM¬d\bÍ\v\12º«IgÊ]|&ÈüU¦TÍ\1dñS½ç-Sv\1cÌ\891n\81lr.Ͼv/\8b\9fÜG¢ôÔ\9b\1f\9aøÉý\88\81[X÷ß\9aùÉ÷U\188f\14\16Õ]Â\7f¾hÄ\ 3Q§g:)É\9e0I+\ 1á\ 6ùÒm\9eån°Ûø^ü¼\9eÁ\8a,\99
+\99ÚʾPÈ¿~       \85Ü×Måà\84<Ës\89AÞºK>ü\93»¿=k  ÇŹ\8e\1a°Äû{¹ÌCï+\97\9e\8aï8/¹\8c¥D\85Âx®@\8aêßnG*¹yF(ÇåáÅ(\92\15X_~\9f\8e\9aêD%ÁP\96f(M\7f\rÒñs\98»ÿ¼]è`g\99óE1~Ó\8då2\97?\ 3\9ds\ e?n\99=a\\90·^TuýÍS5\98ý\11¬~\ 6ö\a\86\89ïÞÛ\87Âê\1e­gGåjQ¬¼ÍfÅh[(\1d\87\ eüw \8bÍ_~t\95M-ËËõ\1e,_\83'ä)\1d\91A°s´\1f\µÛDñóV\84`\8fø\1cé4ðlöúQö\v¾jNÜ\7f\9b\17?'bÜB`9X5¿BhoçQ(|\9e&5õ\91ã\17ä\1c°(\11+¹XÂÁãO\9f R\83ïb9ëï\81\8bÁ1R\ e¶sÿ4SÁ\1e  Á³î\ 3
+._\90\8dx,ö\8eßP¨°\88h\ 1 ²Ë\93\f\a\94\0^Qù'\7fEòI\b³O\a¹ãìt_¯\8b\8a\e\ 4¿u\13:.\12³è\13\93½£KùT¬z\8d\f\ 5¹\8c\ 5\84¾   Ô­å\9a´'ÔÆ¥Nj\f\98\90\ 5³\ 2y¶q!À\1c4ëùIþ3h\8d\ 58_MÛ\81\b\82÷D|e."IXIo\ f}®4Õ öҼؠ  ¾\9a|'æ Ä·ã<A\9d
+× T\1fD©Ó\14SÅ\eú«t\8eN\90CÇH\82Tnæ\86xãPö."'çOç:îÀªóÊ\ fÙÜ\ 1\ e\8dL\ 6m.°á\ 5²\177\99Ø籨\8eT\9f\82¸¨\84\b~8\9c~\98\ 2xMÆtËv»Ô&\8e\ 3z\ f^\86ÈH\ fòÃV\ fíJì£Í\1a"\7f3©Í\8bÑ«ß®â)\r\16*Õúõ\ 5c9,uö\98W\88d|¢PJßTÌÎÆoå¦\86\ 3å£ÏÑá!\84í?\8cæ\vYx\0\17`±Kq<Ù\80ÅÁ§8z(E®\ 2\11`à[Ì©_ö\ 2Ô°z\0\98\85¸\15f\8f_Åý\90;\1e
+!½\ fn\ 6Ö°×;¤Â¿\85Ë\12÷\81\17\94HvöÄiÆ\11¬%\1aÒIð:ÔD\11Êe¢¿\9f9\96\1d\93ð>L0`#\99a\8e}ü*åÓåÙ\1cm}Ç\84àyì¾@Þ\8dfG½Ìá\bÆ|\13ÒcÎþ\8e°\17\89lòi§g´\96\8b|º=ýÒ-     Øà>]·*àëM\88£ÏEO4\9bÞI¸\98н¡n\fc¡ñø\99_\92k\80¿Ý\10\84Ü\17\bycqÛ]-¿\f\ ez1\1fP\1cp\ 1âó@\81?r|\91oDs0/_á±\1e\v\16ÎRg±÷\9eOÇâ{È!dLâ\ 5ËѸÇÓ\83n\97¹¿{½O³§\85Jáû¹»\87"¬½Üñuò­X­\1eï©\9bÅæ×À\1f\13Z\87¥ÜÑë\1d¸\9dìu\84 ¢¿\1d°òO\ 3Xs?§ù\9baêÁ`\84[\8f¹Yèq¯X=O\82ØïóSãª")\88\1a\f0\88Uà'c#Åd\7fÃçÅN¡5(\86û\89Î\92ÍRÍ\95j©T#õb8\fP\7fbo?öE\14p\85sGoÄ\aóKÌú\80å'\17\12\82Tý0r\92/uAÏoó\ fÅ/úu\0Ó4Ïé\92\92R\97«Àk)Æ°}0ká=)\ 3¢\18«R¦ÛíÜf.ßÚ\váãuñ\8dÎ*tÏ\ 2Èf½\80\8bÕÜç\aÅÀOé©Ó~²\808\ 1öWbBþÆ'Êg(\f`\91e¿\ 5\93Y>Ç6R{
+¾%~\ eâ~¤ã]û±wÃÿüd+åÛw\b{\95@\19sù±Ôú\98F`Â&\19öî-ÒP\12\9a\98Y\ f$?\8c\91·å§ôí\1d2p\1f\b\1e`\81H4ü+\1c\v\9d\993çÕÉ\99É\83¼\ eÎ\910\1c3wõn\ 2tö.j\8cÝa\r\88     û\8cx]9EÑkàô\10¥\83¿ÁëeZ ë×\17Å×\9f8oê\9e¾\82åZV$öé©(¤³OÖ°\99ê7\7f\9d?`xz6fXövÚµÌZ3ª\ e½\16?ùù\ 2çmõ³\7fý²/\ 4«|:\7fU\r\ 35}\10\9fÀÜ\84OÓD\98\97O^\f\98\16k=\9c·jI(¶\9f(;\10íÜQõ
+¼'"úX<÷}\12\86ôù58*\17B\0Å\95\9c¾:+¥\94ñë³ö\99þ[ô+\7f[\9c\85\10¬b#\14½\86\8d\989¡À'\93R¤"%PQÛÛg     °\b¹\1aÙ5.[¥ãè¢Ø\16\82·¾ ûпmbe\80\15"ÖÔÈ+ûA\7f±=`\1eâ§d>)v¥±\10T'·(~í¿\1cH *Å÷s°c\9dT\87æ\99\'®\1f+ÛcØÑÛÁHZPª\ f\ 5\1e,\91_L_=ùBÄç{ì"qñò\9bBFø\9c\9eÑ\13p&_ÃQ æ:\ 6\ 3ÿX\80°\7fEüd*ù\f?8\98\97Hé"Â\81çÍÿ\80VN\17°\10\84îÿ;«Ö[Q¨ÒÊ{\85\8bKfÞ"þð\1c>÷¨UÛH'ãÐ\97\15&R7ó\17\83ô\10t\9f´aYåTðR/­\f@ÿ\91'SÁÝ´5V
+Q\8f\96ë¹´«\a\8cßÊG\87þ¤oè£Â8å\99\a\1f\ 6Ô·X\1eé\8bdS\1fläô¾\9d \12\91\8bpäô{\9eD¿Qôñu&©>¸V\7fÃ\ f\8e\92§·s\1e\1c\94ò ²\7fsÒB\91EV}
+&ó\86ùö\85\92\95\13_,\11¸ñø}\91ìàØ\17º|â|Ñï><úø\8cû"\8b\17½x,úbÄ\ 5E$N\9aA\8c>å+\84®é\195\83u1U\1cЧW\1fÙ$\9fN¦ÁÇ\1e=á´\1a>S¦=%*ï½\82Ç/\8aÙ\93v>:½<ÏU¹Y6]9~\88\v\93'ú¾$¾<\11Å'¡y+\9cäO:$80c\19Kòà:R\88\85o\0_\8d±\e®4 x²Æ\1d\0Ç\96:Õf¢x4»\ 5$Ñ3"A7¤ah\94ÍÒÂü\9ez\9b\f\ e\89î!\891_i`ÅWbv\f°Ó\8bH¶ì;Ä\ 3ÇóR\1cÄ\13³t\99Nÿ\1eýÀ\9få!¼Ý,\1a\91¾\88¯\17/×ÖHËì[*sö\16·Dúvp  î¾      ­\86\94éWË~k¤Ç¾ 8#ý¢5Ò:ùBïQ\99°\86Ôã×ÐÎ\ 2Ñ\8b\98\rÒÔw°\15h\96¬\91ÒÍGB Â\17\96\84.8I\aà
+^Z\8d\95\10n\1f\8a6H\99}\7f½\91ÏÛ!ý ÊûOw\1aR|\ 4VE[\8eå\ 2gíø£%\83_~Z\8c\8c´\1e\b\98Ø\9b<\9a\ f»\18)Èb»d\9cÓ&Hò+u~\89Ð\86\96g5þL\9f\\14"\80\94\9e,\89ÒÛ±`\8b45¼Ú\9bkH5I\96жķCÿ½\rR¡Ã\8c\ 3\12é,ÿ\9a´CZ\ 1\8eM\9e\9b\13ë±\1eï\ 5g\ 1öP´B*.>H\7f(xúüj\85\94\10¸RVC
+X\8c³zи\17\8f¬\91ÒÍWBx­ÜX\8etO\98\1dù\a\89û\86\15R\bÂËÑÅ¥ÍX\99ý@ï+we3R_B\9c\a\bix\89½×Bø\94Íù.\0);õøÍc­±|SFÚ\8c\ 5MH\99Fmp/!-½\f\ 4ÃH\9frDí¹\94²BêñÏö*¿3v°\7fÍ`´f¤\17a±o\8b47x/äm\90>\87\88F¦7ÃH\91\8c\99\18\\8d½T»½èÜ\12iãýôÈ\16éåKå\9c·B\8a,?ý\ î\ 3\8fiK\ 6ïÕö\17\8d¯v7m\89ô¾FNl\91Þ\95\13å!Fêñ[\8cµJÜO\939\e¤àw¼=|ä-\91>\9c¶ÃVHÁ&#´ïïùù\83\r\83_hâõê6d\8dôòêëç±x\1c¶Dú:\8f_c¤h}Y\1eë¨\1e9|´C*\10ï׿ÇÖH¯r!ñ9?+\98\90¢D\ fB[ú\8916\fNW|\ f\97DMBÚÚ\9b\97\8dJs*.\1e\9ei\844²¤4WûG¡·Å\b\1c>@{"\9aÇú\11¾9\90\91\ e¸°i¥9$..S\18)\15È\ 6+F¤qqöu¾\8f\90Æ4¤\80E6\10µ¸ïe\9f\11\0in¶d
+_&\9c\84ô4X\8a\9aØëË\vW\ 1        éë<sn`oè.rT9\ 1\17\19¡M,\9bÂ;2ÆÖ\ e\7f\0©°0#\15û§!\19iæ:n\1c\8e÷\1f\1ec¤ÉÓ»Z\r#EX¤±î?ÏRíç:BJ,1ø\92;Ü{\9c_\9f\ 1RjÉ:\8bùöø.âO\1e[?åÓ`\93\9b\97sËç\8b\96ï\988{\89Ìm\9e\ 6²dkVß·z
+3 D}~þ \88\9eZY\98J\e\ 2\80\97Äf¯ò=U\962«§c\91½z­¤LOÕÙ¯Ìçi2ûÄZ¿}vèË]=\94®m\9eÎ\8fªgçû3ë§UâÕã¯E"©\85Ísæý2\97]\ 4l\9eV?ë\19ö>fù4}ùD*+)\15µàX\8d8Pç2¶ü\949¼k=\97²6O\8f\83÷\85ã\87\9cé©Ê±\1a\1f~8\10û¼ÍÛ\95è{\81¹}±~z\91\17~NBÉ\90õÓË\eX\91\7ffï¥\88ÍóÇ\9fQr\96 l\9e\8e~'±A/mý´ùZgnZ1é]\v\8e½\86\9fUé^~ûý÷^±\87\16O[\8fÔÉ^\94\15ì8Ö{¼\14æ{W=ë·?\89×ïÀÏÙ\9eåSÿÃu÷>è»<µz*\8a'ï×\1e\7f2w\1d\f¢çñåç\14\7fvuÍ\8fÐÓ%#$æßG3ßk hùtñ\91   \86ýǾ\ füt\89cðü$\14Î=\84[ÚÛÙièxªF|Sl¤²\åà\a[/¢òQ/¨¡\19k\15\9aé#\v_¸zDú¢Å\9b\a_ôþ\râÊ÷î­/ø\1cZ ßê(þ,øbÕwð\85\1e\a¬ôZöd2\0j\1a9\8c\9c¸H\8f\ 3\10\8e>.p°\83£¤Ïc\15í~¢\7fÒ\ e\81\87·W\82p'a´\9bâ\1e\158©Çä`ç`¢_\82³ûIdþÏGR°Ó>¸\19è×}=Z:ôb\8ftOx\8bÙ"%\ 4\9e¹²AÊìC\944N\1e½kh\rH\9bo\ eH˾\94=ÒrYlªH\93ȻСMWö\7f\99Å\8b\82´<42øU\8f\94n\1cèÙ{\9d»Ñ!í\1e\1eîkH\ 1ËÑðîRCkb0\92¶©5RºÙ´Gº'|\11\ 6­4¢Å±\83\rR\88&!vhÛ!mÙ"EÞx\99ÈØ\8e\15{$¶H\91?rgÇÞ¨\86Tò.\8cc=;4Í*\19\ 5_\ 3£Ç¿É\13q¹èºêwµß3é¾MϽ«\13\9f\8b~ââ}à×Y\v4fÕZ~\9c\9f\9aT\17Þ\8e\ 6#üdv)I?üV@þß\19f\8cÂYUãËW7Àã\8b¨üã\94Ð¥op~\bÅ\95tôF¯OõC0\8f\81ç\82Lwë\86\aB3\93ì4ؽ5g\8d\0=\9føî\15ýèǾ\8a lJsÉÙ\1e ç¹H\86ù\1f\ 1uJJ 4³\97Í\96üº\1f`\195\7f[Ndé:×\ f\7f\95.òpÕÜ\ 5\90L\9c§ü~ü\ 3       \83\90)»RGP\8cdÛÉ\8a\8e\81\97ïêðç!Z¹\16a\8c\ fë\8b=Q3\13Q&\92Ð^`\14ÿ\90ø)åk0\14MT 3Äbá|m±\9aéøÇ\8d>&·\18ß)Y­Y\8dÏã×\8f\10ÿh=\16­fP\9b¿äéýíŪù\8b^Èò\82â!$cË#\ 4j\8fÂÎÌr?\7fåÆ\18Ʋ\16³\1c\80ÝÛ\v»ÇïBÜ5f\11\9f\81ßG·\92¥É\95Ê1½dMÈÖA ²\16çíø\9eÐ$ykηgÎ|÷81Ëdz\9aѱÙô\94^
+S=\ 2uôFÓãñ¯\9c\8d·\12Yz\9d\95U\10Ik\ 6\96«\87²Sf©\95¥\97«¹#=ضGÑ\8fg}Òu\89w%\14AW­Ì¶½V\86l\87\96<8ªÖÖ\1a\9aq\15\93Xý²¿\9aÕ\87\92\ eÙ\11BôZïwÚ¨ô2f\18\10\8fÊÚ\8c6£Sã2±b@6\16¦ôR\8c\e,\8cª\86\ 69'zõø¡ÑW×OS¶üò\8bÙ¢æ\937cÌg&ød·J_«B\13ÕIrÄ\ 1X!þì\ 2\985(Ð:C\ e6Û¦&f½kíÕ~]è\9d³ÖaIn    j'\9b¹\8c\96¢Ò\ fy®È±µX´\93{VÓ\89<%ã\84¢\1f²\15ÄIl\vÙhí]\90¶²\91ø\9eDNLtaIÎüÚPFýRü\13wn=È(\1f´ðÂÌSbØKÊ\ eÒSÓ\94ÀÛw¢£­ukzÊÈ\1f«\a\ 4\9b\85i\95Ïh\90ÅnÙhUuË\92Ç¿æü\ eÒ\8bõ½'kÝ\aâÛ>gf¡ñ%V\92Äí9¬\95\1a=.\:À÷½oGRNÖ}·3hëÒÉFö}\11pôù\r3¸Ê¥s?\7f¢ºT%\15\ 6X7Ð*9Óåñ»\ 5¶*îp¢Ë°'\8e\81ÙÉüú\83Ô¼º\1dpÌhi·ä\98Ñ¢­Í19³%\v\1aÅ?6cÆÀµ\82T¥´¾w¬Ñ\8aóü\88\9eyv\85åÐ9´Övì«bë^{üK\ e¶µ¯P1Gâ[håW\85z]ðÕ5\ 2ei7wy&ç§~\8d7r$¾>wÜ\87\eÙ·\âN¹>r\9b\19Kv¦\19\ 5;}q1MN!\9e\89\10ÉS²$e\95\15pC\88Ù·Ü\88'«Ô^!D\89\91Á\93
+Y.Qüã;½^L.miª)nÃ\19\92\8f\fÞ$¿Ñ§¶\83Åùz\bl\92\1a\ eoy\róa£ \10\86íÙ\92äñ¯EÔ\86\ 6@\951\9dÊý\9cíÈ\0Àø\ e×\8d÷mÇw\9a¹¾pf¹Ç%Ó\8bsÍWp\95Ï0xòú\\1fõ:û&w#T \90M]ºAZ_\9cs\9dv1ùÏ\19ñIî5]ȧgõ\f\16çnUÜ6ì\91£$ĬÔ\16Ì\9aêMÆÇÉܤàÈ\8e\91ç\v\17Q÷êìÒ¹YÁí2$N¹\ 4ð\93\ f\9c©±õß\972$É\83\fJ\14¬
+\8a]¤dÏ5ÿ]\91äõÓ$\0"è6½\81,¿õ"t¾´,o\90Þ\18\9d\13½ÙàÁã·ÉI¸\1dÐùÂE\8eγ"K\97<à~i·\8c±e\vÆò.®\93\ 3±Ë×\0wìò5FIÖÙMC¦ÁèJ££É\84Ñ\95®\9a]i#ó=~\17δ<\a\99ëý\ry§øc\12=ö{R«<a\ 3ï¦Uã2\984Æbk-\84\99ë\1dèKÕ¼\ 6n ç\99k\1f~*íWn\9a\8dN\9eÞù\93.\ 6äq\96ôªiÑÛÈ\0\80Å´ÞmÆ\18çd¡gy©³ñe\11wØõÖ!Õ\97\95ü1ãR\17
+F\8cç7`T\8f\rg½sÖ:£$\83\11Þz\7f\ 2%ßc¦1/í\8aºÍW!`     7ú"É\98\15\ 1#¶µÉ\ 5lÇr\8b-e\15Ï\9aÃ\92§Ûã[\rÇ\18H®A\8d¶'\8eál­\81\18Ê\8b9g¯³ÉëÀYsÝÓÅû\16À\8c;\84k-¢\86ýA¼"7Ææ\90\12µíj\87\ 1ï#\9b\16\9c\8d\13/\88V»M\1fû=>;'âñÖ%+uî§Ço\15\9f«\16-laÑîÖ·hv\19\12Ð\8d\1dX´ÙÀ¼[íÞ\83·\0f¿é£¬\95.w\90\100j{O©\0!Bco[Ý¿³²h\eèþÝú\16Í*w\81áloÑîv³÷\8aá¼Ûn\9då\88Þü.\81ÅÇc\9bÙº2LØ\11a\eA\e\ e­}\14Õ·\94I      @\0\9c\r\9b\ eu¹=øàâÌÕã½m í~K\1e¦ÓÊȪ\19øõÌ,\0[ÇÈbÝ·5³Íéú§\1fÌÊü\19ø¥=þ­\1d\14tä âά\84cväÖ¢\ 6\7fäH\82³õ\11\b\fÅÒ\13\Þy_ Ç^sl]rËÝ\ 4\flͬ\9fÓZ\18\95s\17ÆÕða\eÿÞ ¤/¿x-Ü.âC\11Ö\8a\ 5Lµc«WC\0æ&|´]\v\r\91\ 5\0Û:çR\80\19ê\1dl¿\8a\9fÒ²\Å\1e¶ñï\rPäµp«UìÁÊ¿·\82âñ¯\84ãj5t^\v\15\vÓÚ» ¶Y\rMk!:\12\1eÕÖB\19ËÒÙ\97\8d\8e#¡Ñ?Z­\85ÚZ©?<¥\1dðõ\ 5\80®7ÛpÔÀJ¬\95Î\19\v\14,¬ð(]xº\8aM\ 6\14Ò\85§\v R«²
+\8e¶Öȱ±ßíLJÖÒ6"zt©çN»§ 
+(?6\e<ØXùÕÇéÌ$Y+©$É.ÔË´0Å-\96¥¦í²d\9bO¶]\98Ú3\87 Íæä\9a}¼ß4\9f¥·c¥\vå\82H\9c\7f\1c8ÇFn\8f¼\15\0Ô¯yiÑÍËZ»7\bØܵ\10¯ä\98\9b|²ÝÎ\80q&\91$\e\8eß:\ 2³q1
\84Ãá[\90\btBU\96\89\84\v¢\9cÒÂ\ eÊ¥®Èr\ eHs\18¤Cá\16øôßf   Þ\1c°¾è÷O\ 3UÆÕ|±tìݪ\82ÎãßM\r\9ds\ 5ÝRÅÐ\865tÎ\15tRôº}\r\9ds\ 5\9dSµà:5tÎ\15tÆjÁÍkè\9c+è<þÝÔÐ9WÐ\99ª\ 57®¡s® óøwSCç\A\87Owì \86ι\1f®~ÚA\r\9ds\ 5\9d>\v·M\r\9ds\ 5\9dì\8f­®¡3\1eH¶¯0\9bZyÛ\8egàí+\81r¿k\91d\97é­\1f\8a«\ en\9f´\83.ê¥t^ß\96'kë\87+N\84ºÏô\ 2\9fêë\9c%·ßã«\aìO\9a­Å§å*\9bå\93fa\97Å`\11\17I\14ã\1e\9f\ 3°èÖãÃ\1eìêÊ9÷ã\8b¯Ò\17×L7mæ¬&ɾòqE\1aÌ\81¤å\929\94\1d]³hÎ\9d­iFujm8Û³^\ 1Õ\1aGA$Ý·;\fòVÚÍÞ\9ctvÔ²\98h½¡9ºîê©\9b\95ÅnÆ\93\90ë%\ 6\95õeÛ\8c±Rìf½mc\8e\92V\16»mt\14Äh-\811\ eûºúÐte\18\82@©Õ\fÒº¿&0ã\11,\88\11ã\8e\8d`\8aÉ-*\1f]Ú¬ÖÞ£ó\11\a]Ðë1|ÃpiB\ 5Û"ÓµJLå:>·%\8c«c{Áj/[ç\8f\99Sg«\13\87\91å4I·lU@´Ù\8eÕ m_ØoU\ 5\86Ï*ØÖ\81\9dÝ\89uêø\9c?]àú\9c]·l{ÂX\7fæJKZÙ\97¦eç§ç6$9¸ÒV\19x Êþ\f¼:u®æ\8f;Xu\ 6~\8d:¾±ó·\ 6öרã[Y\13c/\f\86\1a^\19Xc¼\eÉÒv>ì+SÖ\ 1f\U¶äØË\8a¨e-\8eÙo\85¬=HÙ¢mÊ1câ\97\15\97\ e:ͳ3\93?¶a\0ñUYYÀ(«ºmÞÒ¡^Îl-ì\0h\ 6Ƕòñ\96\94~¬Ðîùé\81\8b Æã&Ø[Jí:\ 4{6ß\88 øæÞá6 P\19\96eÔ¢\8f\99¶á\89¾TnÃ\19\19±\8fyìKÜVëþjvØo1\9aÄÞ\96\19ºï*¬b\87\93çRqþä\89úµ\13w~$õ:kÇ\8d~äÙªªX©bȱÖG©ô\19¯\93¶X
+\95\14Oɱ@ÎÂêØWDYÍÀFþ\18\90äw\9b¶Pý1[>Í\83nÕÕ¹Ì.àYA\94[>\99wq\8c" Tع\12\81U\95q¶$\99ê\91Q9ÛZ\19\19\a\92\92ë­bN\15vî22«N§»(\8as Éüí\8eSò|fÊÈ$\ f¸é\8a\98ÎMFæ\94¬îm\7fJíÜEFFÝã[\116\8cηÉÈ\18ï\1a «\81í\87f\91\91ÑNw¸/C[?#cQ-Èýnz@X?WK\15©\9bÕç­\93\91±Éó#Ƭ:iï²8\axø\92dw§$r\8b¥Bó̵oõ¹q7Îò´º\8b\9aÄÓ;ÒùÄ\80\9b@CÊÂUw\93ÔÁC³:9k\\91Ý\94¡\9d\84Ö?$gZ_¦UWG\17V\96\8f\99\8e.ØU\v®ª«[ï,£å        ÕªÛózÎuuÚ\1açX)¼ú\80\b.®³ÿH\95^\92Ý\1dÕ\ 3Ìû\ 1Ó±uh\v:\9fÈ\92\16:ÏÊï{î¢\1eN:\ f³"-¾u=Ü&ß\1f[¿\1eÎú\14ô®ëá¶:¡êº\1enÅ       Õ\1dÕÃa\9b¼µ\ 6®ª\87³ü"¨íùÀMëá̧¡\94í¿ÝÖÃY|w\14\ 1Ûq=\9c\8b¯\ 4ì \1eN7/ú#};®\87³\88Ål¶uP&eÓ\r:S½\98à,@®ÏD\9a>1lï[º9\13¹tJb3Ý¿Û¾¼\1e\19!\97'!WÂq:\19ìz\87\17Á1\ 5ÏëP£úc\18ζ5ö\12\94å¸Ùú\füj\8b\98\103\9fw\96ußQ\r-¶òP  \9bs!\8eA   ÕÛ\7f¬+½vR\11u5÷lïÐ+Àîí5ÇÆ\8eÙªa饹A9©É\e\a~ï@\r\9bÓ\9d|\r\18ÃqRCwÑ+\86³\85\1aê¡\80\12nù­\e        \8eý~ºõ×´l\8fY#`ÆO̬ú\1a\9a\1eÔÒ×\1aÑ\b\1c\16j[éJ;\ 5Ôº\8aÔ\87]T¤¾üî°"\15\80í®"õåw\a\15©ä^j\17\15©­½\8b¨3\14w\15©\0g+»©«\17sõU\91\95ÔX\86OëV¤ºÿ\f´>$¶>×\87\15Äᣩë\1e2B_ÔÉ\ 4£Kj\98       ®\98\bwy-¹\14ÎÖ\8eí´\14\ eùc+Oô\18\a¹A)\9cݼì¶\14n«¼¥ëR¸õâÊMKáLß z\17ÿ-¥p\96Y\85\9d\97ÂÙåÇ\Æg°~º1\ 5¦ï';\14>\19\ fH¬÷Ex³?ÖÜÙ\aÕPÁ\99\92>vþö \8b\ 42\ 2\10ù\16>L{füÈðz\9b\vÆjôB<áj\vÇáè\ 2ªò[ÊÑ鱸(n6\91äR"tÙQ\8båAÎ\0]K·ÆY\8a³âúá\v2ÙÏçO¶ø$Ü7r\899_+\89o'ï'·Å\ 1éñ\17øÄùCq¿wÞ(\9eF\1a·'\93\8f\b\ 3¿\95ëÐ3P\10\1e_\84.\15Èî\15%\9f\10§{uùä{\8bb·ËS}-\16*ØÁ;\89J±Ûþ}³®O_\19JÀ²\99ÂsÓ®ØíѶê\fÝÌG:TØákµm\902ûèRíW»b·\15\15vÓ¤=Rt­¶-Rt©ö\97]-VÈXag*v«§(\1dRc        \18¾jZEj.vC\17d\ eí*ìè\90C\85Ý\9eÐ\8aÛ"%\84êqÝ\ 6\8fÏO_\16\8aÝÞ\9d\8aÝ\ e\18{¤åëý'\réÒ}|þ«þEË\ eé\8d\ 3{/«÷¶HÁ\8e\95Jw\82qV\ f¤\ f\16(¿É·Ù-Â'  Wý\92\ 5ÂÔOÒ\17sOâ#\9cÉ»\80\18ÉLæ%mé\8417i³#ªEI\ 1\8b\ 5µàtæ~å\91\a\vlM\85\8c{DE\17\a\9cÜ\95ö\9c\98¾ª±Í¥_Î\9f\12_:seOTaÅyRçs\1ejôº³\9bä¬î\91³ü¦ÊV7É­\99\85[úèÙÆÕ\90\13\8f\9f\1dqã¹>ÇKäV\9cëÛÑ%r¶ã³¹÷ÍåYÝ\95$­¼kÀ5Ó]\1c¥4|KmóûãÜëËdÕ÷ò­\8e»º»\80nU¦wýjºMó0ëUÓYÅ\ 1Z\16nWÕtVµtÖß\87Ù¦\9aÎ*'h¡/[VÓYÕÒmQù¸Æ6¶íIû\8d«éLl1×Vï¨\9aÎ
+ÔÊ/\84¬]Mg\15Ô»[\91ש¦³Ú§Ñ­\95;ª¦³ª¥3í\8cì \9aÎ*Ïbü.Ü.ªé¬ríZôº«j:\87ï\í°\9aΪ\96Îxvt\17ÕtV\8b6\9eý\9dVÓY\91dþ²ñöÕtVóçñ¯å\9eº¨¦³\9a?ËÓP[UÓ-\83Zy§ð\ 6Õtö¾å.«éÖâØÆÕtˠзÔv]M·)ÇÖ«¦³\8a°<;¯¦³\ 2\80k«wZMg\ 5À³ój:«Ý\92¥3ð[WÓYÕÒ\99£×í«é¬ÊÇ\8c;#»¨¦³ª¥3¯/ÛWÓY1Ãp[ÖNªé\Trí \9aΪ\96Îá>¾í\ 3ÀÓ`QÄ\ 1 é~±¯\15.\86Ë\ 21\9f\89ï\16ws¸+|rm-$ïb×÷ÕY\91äè]lt_\9d£wá\8eO+o¶5\b©Ê%s\9dø\99\vÇÂ\9d\b\14çZ\81\82mÕ³5QË$¹2\ 5®n\97[K\9e¬H\92Nw\9c¹¨§wË'«\83\14N\16Æ\81O=·Úk¨ä2FD\16{Ï£sã\92`qÌÚ!3§[Åì/º[£fÍú\9a;ãw®Ü¹äë_sgoaÎ]ì\ f»½æΡ\92Ë]!\9d«o\82;\9fO\96/ºÛr@ç\vàضÅ-.®¹s\93Q<_ÿº\1fÛ\8c¢ÃEwnj\95
+N×Ü)µoë\9c\ 3¶Í
+%Oï"ûVc^ë;WÓêÎê,N3×®\8a_W\1fQ\82¡e\82[×òL«®Îb\80|ªgG­\véV\W°Z>«òyþ\1d\14Ò­<ûëqUah\7f\88ÃmU\1ab\f³\93CdUÛÔ\9fY\92ÝÜ°\85mär=Q}d»ÐY\7f\eÊn¿\a\95«Å7¸PÁ|\1aª±»ÓP\8d]\9e\86j¸<\rµâ`s}äVùVT>\86¶Þ
+ÁPl?\aîñ¯\ag³%Ï\10%a8Ûj \86b²Ýv\95«Ova`«\vk\1dn`7\17Öª\9f(ÖiN÷ðÄy\95vÿU@\ 4¬0_Ëó÷ù\110ÊÕÉpÝÚeËÊ\9f^ØÄJ\17÷½:8\11È[\v\99OPC\9bù\92¦\15\91¸í\19껵\w\87\9bòvv\83!Z+wV±y?±-dXG÷g\ 3W\17\r­®|<
+oëN\14\96¿R¼Ñn5\86³^=§Í=VK\9f(ÞtTæ{\12×¼\88Ǥ Î\85\fkîð"ß+¼TÈ\10ø]Y\99âR\r·ºáN«¯´¾ãn#5\ºánó{«×¹áÎÁ\eÇwÜí¢ò±\18ÙÑMy+ÔÇõMy;©K²»ãníQY~Ú{©.ÉÍE\93kßp·â¾×èr\ e\rwn¿j\8e\ e©ì¤°K>®a\1f½º/¬mí½¯¨\85õ¸/¬míµ-S\ 6.\82PCåã\ e
+k_~­ªÛ×ýÎ\95\ 4gÝl\96Õ7"\0Î\ e
+k\11\14å \93s,¶\1a\8eýwáôGktß\84´-czX«¾ÝB£§Æ]Ñ\8fPÌB\r\1f·Îkéî}³ÿ°\8cÁ\rpQÄô.\9ab-ã*¶²\8ci©"Ì]Ø®\9b\17ÛÀýqëÃX:­|t\95¦vSÄô.\9ab÷ÍãJTèé¶\88I½SxÙp\ 1Gïí\róZ\8e¡T\91\1aw[ÆäÊ1,Äc&Ç\10a)ÄW¬%.\1dæ­c\88Ï]¬[ãÊ?~Û~©Áò\9bõÒ\17Úm+ÂV\84Enwl$\8e\99ïhÜ0\81\8c@Y&'7ña\96Îo¬Ü\p¼[pûë\1eÛ3¼ä¹ªz^mÑ\9a\8e_\982U=;Õ¸jÚK$\84÷\98\15>¥Ì¬W\10ÅSÒ/\95èÝ\9e²M\8f¿ø$4o\8bO%1\97¯0·ç\ 5>Þ)\14øD\15\1dãlL\95\85Ç?4\92'g\97L÷°ÝM\87ÏVõp\1e?*N{v¸èî:S×\8b\92¡\1e.rÔ¹²+ÂK}\87ýǾ\89Þ&\e\v¶ìkÿf{B7a\8b\94\10nùk+¤\1e¿t\ f\9b¾JÌ\8côÃé\9a»\18§Cj¬\12\13g\99ÈL\97»0_tG?~×\8eljÿö\82¶¥iââ\83´,Â\ 3\8ea\ 6\1f\1f\8dtwÎ\99ÊðL·ë\19GúìTù7¢\f9XsíßäöÖ\16éa­÷ݵCÚ³BªÜû\96¾¼~´e0Qº|.Û MW\f\97\17\9a\91^c¤º\15y\1f«¦L\0þM.ÂÌ,;u¿#Û~òYk\ 5÷KÍ\15D:T\97úÉËd\8d±p:\15Å\15\16Ã¥»\9f\1cóÄ9«ÕÎéØdDúº\9cé\16³Ã\89ÛócNkósѸ¯@¹È\90Ø\97$ýº%Iª\80p j­£0v\85\8eíèhÕsÑö`\951\aë"\93T\ f\98\8f ¹\98\9bY\9e\8bë\1d­r(\03\7fyróª´U'4ås°®äib\12ÎMÏö\14×9²¹\8a$£hZè\8bk¦»?¥\85óÉN¥\80öyâ5õÅá\9cVN¢gùl¬Ñ\Å'K\9b×ͨî¾LëJ.wæê­ävûÒ!\a\8b¿\e·\93¯Æ\95Ðìï¨\1aé­´\83]\1e\18ÚËöù±·Ò\ e¾Û\bsnµe½æw­7Ì,\9bÏ\8e\96\11ZT\ 3è¶^leÔ\82\80Ù\9fÒr\93\1f3\1d\1aiS\13sÕlk¯æ<f·\16¦M-v\15#»H\a»L\ 6\v¶gæ¤Ý\ 47××\19\98uaÿ±+«\94\1dæ\98Óµ2øË\10\86\ 3\ 4åÕ_]0û#¶\91x·ì°8®WH\96\9e¯¾3Åu!Ù\9bù;\aÚì®]cµÊy3dc\15\92\96ë_\ 2'=Ûï\1c¸ðÆõ$-\9dSÚ¢\14Ðhï-K9Mß¹²/\ 5Üjþ\fu\16\81\93ûØÎ\84á>nZ÷·\ 2\96pA\97±ºÖ\ 1ØÊË\7f×áØÊû}Ü\ f\92Ú%Ç\92»ä\18m\vl©\xÙ;Ôôe\93*@·5\80æ\13Ý\e\14\88¹\b=\95¯jØ\81XYvìª\ 6\10ÍþæU\80æù³«\ 1Ô\9dPÝ 
+й\86ci_lÃ*@\93¨ØF\98Ëç`ífh\9b\eõ$\8emZ\ 5h\98\12\87\1aÀ¥\1a+[vls£\9e.FÞ 
\9e$c®Ä´_)ѳ4*\93÷´ö¥|kÝȶñ¥|ÆÛ²þ]\97òYe\15v\7f)ßê\eÙvq)\9f\14#\avÃ'ÛKùðNâz7àmp)\9fU\16\97ò9Þ\8f¼³KùÜÞ_¹Å¥|\86¬\ 2"ªF¿Ø\10uuçª4ØæV¿]|\e
+Ýë·\93\9d}\ej»{ý\8cC3\176mpÚÖò^?ç¬\90E\8dÕF÷ú\99¤Òt«ß¦ß\862ßëç\9c\15²\8dÄ×¼×Ïf\86ä[ýì¾\rµî½~®$yë{ý\9cO\86è2W[Ýëç¢\92k\a÷úI\95\vé\u}Ùò^?ç¡-ß_¹Ù½~ηúmt\ 3\88Ž~Î\ 3²>¡ºþ½~\96ÓäüUó\rîõs>qfó-h#wÜ\96\1fÙ\16\1fé¼¾­îõs^èð.Ï\ eîõs¾ÕoÍ/PÙÞëç\1cêÚ\9c\82^û^?«SSÚ­~[ßÇ·\83\9aw÷÷ú9CÁ³¿\83\9c7Tt'º·º×ϹpÖ¢"u£{ý¬7T\94[ýL·3l|¯ßò18ý­~Ê9¥\8dËSä{ý\9c\8d\99Ç´vmz¯\9få>\8dêBHQÒö÷ú9\1f¸6V¤n~¯\9f¡~kéV¿¥ï\mx¯\9f3\ 3\95\eÙ¶½×ÏQ×î\90$ïâ^?çÝá5îãÛâ+\1eÆûø¶¯{°¾Õoýj\ eë{ý\9c·\88íOÛ®w¯\9f³'/Õ¼o\7f¯\9fó­~»©J[u>Ããßͽ~ÎûÍæS\ 4\9bÞëç|«ß\16÷ñ­qHÃé>¾­?¦£Þê·\93ûøVÆÒ.¾Þ°|¯ß:Wñ\99,Ìv÷ú-\15[\18nõS+\86¶¼×O\15/Ë[ý6©J[ßͱ\95±5ïõsrs^~!Þßɽ~»¨{]}¯\9f»º×mïõS¡¸¼\e}³{ýÖ;seq¯ßæÅðê­~\86û\91õ»Jk×<9Ýêçð\95³µîõ³±c²\e°´\8amx¯\9fóA§¥\9cÒ\86÷úÙ\95ÇÑ«8æ¾æ)\13\95[ßë·^\¹é½~\ 6õt«ß6§\aõ÷ú9K\84Çe\92wÕ½~Î\8e¡º\93¸å½~Î\ 5±Ú\8a¼Ý½~ηúYøc\eÝëçä\ 4I>Ì.îõsëÃlw¯\9fq&Í·ú9V×®q¯\9fóâ°¢\8aÓõ½~Î\8b\83ì)¡­ÊøÒòP£\1dH\96Ö\85å\13\1f¦ïJ%\ f¸ABZ÷u©]¼\8bi«ÎÎ\aï\8de\8b&;FGo\8c»7\87\ 6µ\ f\8eô)/l\98Õ\vAp\99\80R\ 2\95Ö'»Í'\88PE\98\1cZøb\89ÀE<Yã\ e\94\99(R³¼/ü%^'bþÌaòá"\95O1\91Ù÷Yb²h\ 5*½4\17>}>xÚó\9dÍC¾¼p\93Øk¾1\99\83ÆÃ~Ñ?\187j\81Þ÷4æñ3\8dÚï;;èÖ¾r\83\8fËïj¯Áq\97/\95ßû\ 69­~6¾¯ûûrâbqÿ^\ e\ 5ßß\v\91ÐO3õs5ªG\8e\91§Ü\ô7\82\ 1QL\1eøö&½IÂO\1c|\1f\85\9ej\9dû\b\17¹\bf\7f\ fF5¤ûþqQ\14O3u_øµ|á£ø«aä¨Cç\b\81\12Âí\83@\94÷'\97Dùêò[\14û§1qñ\9d\rÌ\ 2ÑË6\1a¸O®´Ìþ\96"'éËg4%>\öF\94îÙwqöu¾\8f´òªgi\90äyÁõ¥ÙÙ¼ø$äkÂIþ¤£]\ 1)Ý#\18à\7f\995$éÆ÷Ý\ 1øÉbnÌ\ú\1e\11«±J#]|Ä\ fÂ\87þÇúAúhÈûë\8dòyà£qvBs\87\17LD-\ e\85iz)ÅØÚá\ f\88ED\98í g1\9fØ\7f\ 5IF\ 5\9c7°´\\89F}*èÕçÃ?4äV\91;!ç[ymhÚê£çÃ)\eð\80àL(ºôÀÿÞç\12óp1ÂÑí\ 4_¢*9h»8Ï}ÞÝ^æ+ÌÇe\84K\9d\9c
+ÜÁM·ðz¾_Á#¥øf¤$©5ÞUÉ\96\1f\82è·`¤\18õ/\84`åì\8c,½e\8e=þB¿\95 Ñä\8cK\9dÁ/G$\1e\a1ê½Ò\8d\12\89Öo\f­ñ\aèDD\f½\r\væÉd\90<½Û\8b\8a\ fà`\88H¤è\10þ\138\96\9bÀ\9f\99\bþ\13\7fµéæ\17\1ar\18N\0 ö¢ø·äÁññ\87ð\1e\12\9fo¹¯ÜQÍ'\ 2ÝU=¡Qbü¡>\bë\1f\14ümõ\ 1:9¬{tGvÕGqý\83¯\93\ 1¡{\10;8ûV\1e\\86ðHÉrm¯¥¶Epg\8f_ê^~\8bwÔG1\1d\9cò4C ¶\84¼$¤.    T°4"+L\8dB\7fR\12ìö\9b_\85}\1d\91º´§$úJÇuL·¾\1c\80°\ 4Ñý0×q©S\87) 8×\ 4þl<Ù©\á?e°\9d§g\12\87)D¢)D\12\17\8dA\12\9eÞFñS*ÄdT¶ÜÆ\15,Dè MPÃ\86¿\14åBo¹#âþ@/\92J9¦\14a\9a¢WSÔ     `\13\9eÝ\80%t`ÉÄþì8rw$2Ù;ú2Ͼv\83R,ÆS¡§\86O\96äæ3\95\1fMj³|õááC\134*´è\ e\14&<Dµ©£\8a\95\13ä\13>HrN\15\9fÎHI\ 1\8a\9d«\14þ\r$¹8¼£äÖÅó\eV{ª\14j½/­\81heÓUÍ\9eLý:\ 3 ê§\95\ 1@5ï`\ 2\96\f@\8a>\86ß\8eÏs\89Ùô\14[\81â¢U¿²4\0¦ûseY<\1fI¡      \98è\90´cu\0\1ckmDétÿ\vê\1c\8d£9\bÂ\9f/3ô4\11)Ý?V\10+_ä\13Í)2\88¯ÙÄ7bÂ\9flXÒýÖ^\83Æ\90Qt\ 36Y\9e\rÐ}\l\8d|\8a'XÙïEIL{uöX2\9e\9fw\99gËä\bX\86\17YJÔ\1fè\ 1\19\r|'\90\1e\87\8cºÏÍQη\1aQI~\ 5¢Î\80Æl\ 1Û\9f ÄÕw§²åË\9e%\88T»z*Ù\83,{_)|\fò]ð\1d§¼Ü¥\9c       ¡É¹ÀQR\8d\ 5î¤%Á ËwÁ4Ìï×\95iWÍÊ\ 1Ñ;-Kñ¼\9câ^®­ÆëÁIâ\aû^øbe¢·\97Jhë'nC·Ý^Ë\vù\89\18Ñ;<\18ÀñiC\aàì%\1a×G|x½ËÞ½\87Ñ\19ã\9b9r_î\f\92\ f\85äú\1c>QçºåM*\90?¾Ò\0\98kÞ1\88\85\ 1Då°¢¹t\88'R==\9a!°¿ÑK
+\96\91,ØÃh%\82~\8b«m   µ\r&,ÚøEÞÅ<(J\82F\ 4ãO:Î+£Æ\1f{øP¾ip\82LæÅ\18?\b\ fn^@@è²ùc\aÈY\94\aD\87^ñýÈ\8a·\83>{ 8:¡&z°/»AûK\83\83y8\92ç\85\ fUUï¢ò\1aßû¹Ã\8e\ 5òG\90ѯO05\1e¿áÂdì\94\12Ç\92ìÕ@.ا\16$Bº§}å\ 2­á{
+5º\8aÿ°\8e\ 5Ïb²\8dY\0\16\ 6]_­1!Txê¾)L\88Ç\f\7fU&¼éY@}]«,xÒ³@ùæ\86²\93\98\9dg\7fW1¡u|©1!ù<$Óæ\93Ñ:¤º»£¹=åK\14NL\88kÒÿè\9b$J\92\1c\88|óÙ\9d\1cä\168\v\87E{áÓ\98à£gÏ\87*\13\1e\1dä@úµÄÅ\17;Az\94\ e\ 4Þ\9e_\ 5     Àý\ 4\ 3@ë˦ \9aSM#\9cõA\9d\173\88\97ß-\87ñ.j\0ìµÒ\11D{æv\18ò\1dÜË zó-\87ñ½0\89\94\12\17ª¡o}©4d­³õûñ\86Ú­\0hN¬\0ÀXÜ\83x\99nkaêï6FÊílÔÛ¢-\r\1e¿»aôf+g#| \ 3pZø\9d\18vF²õï-\85ª>X8\ 3\90\11ÄÄ·\9a\95\8eK\9e¸§ZKº9Ò@\10\95\8bfGß³ù¢ÊNSG-!¼V\8c÷#¿OUÎ\92z\19\93\97D\17\8ciöìç×¥\8c5¿gÛMNs`?»:\19s\ 41^l£®øntq\ 3£a a±çL\83$cNªÒnoªñ
+\80oQ\93±\rA\fÜL§ã\8aÜ\1eÏ·Ñx\0ð»ØvEn¶\7fõ\7f>íï\e\10ô~%\1f;\9bª\ 4¥úÊ\88ñûN\92\8bLôæ¹4öÌÔ\90ùM\17\ eF/Rð\1c8iJ¡0Jgã\1cNL\8eÊ\94@Q­ILUÔ¸³\12Ä¡\rÚ\ fBþh%\8c#l´Ç\89>\ e\\89Ê\7f\16âÈQ«ÄÕ×tQ§> ËÒ0\16\95ÐW¢\e\ff\94G\99°ö\0ç¸\94\a¹¨ö\80
+\9cÖ²Ê\ 3!®{ðºxË)\ fj\84\1e\8b)"Äa\8a\1es9\17Ñx§Ç\\16\ 3\1dX¢r-!Gâå+\ 2\7f\7f,\15I\1ep#\90§ò\1d\85`C4Ý\9as2\88z!\82ºDá\a\vëuý,¦Dw\8b°\1c>ÕkqÜ\ 5\10<\82`×o\bä6\93ð£\8bþ|¤ð\19\92ýpòô\16ü]<\83¡\83xHÉ\15\9dá¹\ 4,\ 5òHFÚ¼\8ac,I>\9dL\1fõÞB\9f\85oF¸â\87éý´>fÅ!\ e\18\94ÇoÚ\ 1\99\ 3Ø\9bÄú`\97êø\96ÁÞ\11\1aXæî$SÈß\1d\1e}\14¾Ùê4\7f\9b\1f? ±ç(þ9ü&§\81:\8f}5\17\96T\ 5íC\9bgdaÚ5MlZ\10ùÇÁ\8doßàüg\14}ª%$ýÖڻǩ\ 5ÄþFXú\8d\7fJVP\1a¨       Bu|&Ñ\8a¢\r-A\8c\83^%\ f\13Χ\ 3rì+I\7f}"\8bÈã ¢¨Ü\eÌå`/\9eèïÕ\ f%y\81xw¦¤Xâ\ 1èÒ\8cáÓ$8\e+%hP6\16\8d%\95\89\90\95\83\9f¬¤rªfÁ;÷\84¤whë\ 5\15ÓÄñi\19\94ä|\92ÔÐúèX\ 5_\94UPO\80©'ºq\ 6\17\85}æä-ÎQF\vþ©L2h¥\94\91\91\12Ä&]\9cµ\aüpo,\90Ñi\81(\9e\1fO\bèrEê´òM:\98$\89@ù$¬\8cï2\82\r\9c\96\9fÿï¬\87á\92¤\97#HÎ\9b¸Y\f\95Øÿê\8f½QÏ\91'\91?#É»qw"\88½Þmï_ó⤳\18õÆsoÆ\9bÈ7
+ggéT±×\99t{^ü\85\8aÔ\a«\v°%ì²ä&í¶\8d\8eÐÍb|ñ\93+\ f*û7'­â'ÑÌê\ 4\1e¯\1c¡då\ 4m)\81\8bd\aǾÐå\13ç\8b~÷áÑÇgÜ\17Yd\1a¾èÅcÑ\17#.(\88\84\9b\96\e³:MxbFODZ\ faÂ>$\89®E¦1{ÒÎG§\97ç¹*7˦+Ç\ fqaòDß\97Ä\97'\ 2\7fá\13ïÆ`˳¼}Xãlwɤ\ 1\85_\ 5\88\9da\ 4?\8f¾èý[        \88\7f\ 5c­=4¾sôãÈ\17Ë'ë0êÃ7_¨?Ìúbãë\17\13çвçw»R)\99ùuÖªõW*4ûë®Uë¯TúuÇíZµþJ\ 5XÖ^«Ö_©ÔSëk¬Uë¯T2\96U\8b
+\9aZ»EÅÅ"åño\ eÑýú\ 4\92ìr\85Úf}òø-W(m§Ýx:\ 6Þ\81¹UÔ>ãBí±Ò#ÝWÕ\1e\8cY\10Y·sdÇêH÷+¾hèôÖBí\ fÌj/I Ø;iµ,½äñ\8efXý¾bª1\95;µ~QBµ\896\18è J\r#M}\9f\v%ê"-+;ÊHö~zh\9f \12\92|\8dÏÀ/þ\13~4'Ò\ 6'\15Èù^åÝÉB\1c\7f\97ì¤\1eÅÌJô\1fçqiáëG3\11¼Ý\93<8*\9d[\1d\0\83       »¬*Û\1dò\ fôàNÞJɲ!M{±7\88t'{\12QH®Få\95ó\8e\8c[ìh&\94µ±F¨{\19¤~O\92ÿe¤m
+X\19Ãx|\927\88\1c\84\97¼~\ 5qØÊÖd\83_:Þ¨\9c\ e&\8cw\88)\19­\83Ò[Ê´5`Ü[\88é7\ 6:éªioÁç\9b\aÕäʬn\ 2\80£§p9NWòJ²ýd\12\ 4\89]hi`*È5\93\86-\10fßçç\ f\8a
+\80Ρ    \0ÂÂ't Há±Lj{z²ò¡\15\19yy\89~ö®\84½8$ Y,\9fJÛý¯ÒÖ\14\13ý«qDÛ\9dDµ½ ,\ 6\1fq\8b\94\ 3¶NÒ©\a¼ç!\1fnðøù\87pKÙ\80ÀB%çÞÍÛ\ fÈ\83ÜpûA:\8b\15Ú2÷N®H\15¬Î6\fÒS\85     ¹dÄðùï\ f\85\ 5tBc\ 1¢f Û~@>µ"ɶL8Í\fÆ
+\13Â~ãöCÌí6\14þZ \15\13NV'\1a\9cäà4S\9fk;0\1e¿\8b\8d(\93\1c Ò\8b\80ÂE¼s¤pQ/H\8e;YÈà\ 6×\ 2±\ 4\0ߪg\0\80¿©¾\ 6\béF°e\8d\aýn©\ΰÅ0¤\83ØË\0LZé\b\ 2ß_±î0,Îûm3\8c»LÂv[\ f}\97Ì\ 5\88·\1c±Öö¨    \0:O\1eø\ en£Ý(B\r9\ 3À»¥\8e ¸yx;\1a
\88r\12Ï\ 4Âål\90ÑZ$ê\82\ 6\8fß\81\8a;2¶Í>-\19}c%\91Òö\97×\1e\ 6x3n¥RÖý%\10Ó\ 2±\92\95NK^ìà\8cÄ\0f{å
+¯YKf\1fí ÿêz\82c\15\92{
+?¤Ö\ f\9dÇøÐ÷«í\85\15ÎâuO欴 ª2æÄ\98ò[ÜÍüÚÏnù\8b\8ei2¶Ñä\94§\197&C/cf\10\95\83\b«aTb\ 2¡ÈØfF\ 3\9dÄ#ÝÒ Ë\98\99\8aö\9b\7f;\8doOIÝtêVd÷ :\all»\15\99ìÄNâ[i|\87)\98ÕÕå\8a\8cOI¥È Å7É3ü¢1/\1a$#\ 3\16Ý¡Ñ|Sbà\8b±\1a\ 3ÇÔx\18â·¡\14ñ*é\9d¦|¸L\8dýäÈ0\15\ f(¿\91A\1c«È±\96îô\1a:(\96:\89*'WùÇgtØ­\10W^\14\12j ©??
+ëл\9aè\f\19\8f£©\a\11ý\83ZD:B\8ag¿ª?D
+\86´§¾\93Ð?\98\16´C²¦\10\ få«.õçcËwAõ|ì¥ñ|,\18\ 3õ èe\1cÇ        H5      )¸\ 6\1dC2}IJQgåô\ 6ýy­\87Ýþ\8a Î^Ë\81)ÈbFÝa\8c^àM.\1e\89\17\92\89ë\84|rõô\f±íZ\ 6Û¹¾Ã`Ñ]*Çû8©\83nÒñË)\9f\18\8d\84æVÇ\16*t\9a;©T\14%ÝÎoøaü+\9c¯w>kÅê\99¯a\11\86\16\8cIkÓ\aGx*T\11\8eÕä¬\19\1e\8e\91×\86x];ÑÒ½©yý W~}J\7få\e\8b\83~é©[G©ö[R\93^|o²\9aÈk¾%\15ñº¥õgSOYõ¼ñCL> z]@æá!¡\88ý\ 3Àn¿¢\80ë\81\92\ f¸ b\82eì!\89\7fW+'RÊÙÔ     \1a_âP:".¿x1\96%þª\17\96¦DM\1dayÁÇÂQxHÈÇÂ\1fJ-9s\85\82\ 5\9c\1d\r\15ðÛqöTK¦&¨bì9\82\15MÕ¦\18\96\1c¬k¨:ìQ=í©Üà\ eªgúÞ\82úa\8fÔ\19\81ê\87®å*_¥Ô\17§_Qü\167e^ñHÉÒ[÷\19\13\8ct1&)¡\94g\ 1ýóøu\1a¨\9d\v\ 6CiSÂtb\ÙoàÑj\1f\97ÇWÎEðÑQå`ð쿳\1e\90^´Ýð^\1awõ[\r\1e¿\1fZ\1a½ùb\8a:¤ÞùÞW\7f\kýé\89\1eÒ+ýCÀ?èÿT*åe9ô/áM¡ÆZÛ\13Ä]½TÈ[\e{üï\89¼8/ö;óþdÜ\12ÿx3¨éñ¢vwVôf¼Rßwè{ä\r\ 21Ä;ô\86G!´½ñ\ e\ 4¾{\bo\1eþ{ü\epç§ð£\b\7f]y\888Ť¼_\1eB&\ 6\81?Îá\97\1fhúÛK{/¼Ï¯\84·\8b^¾ñ\90\14Cx92\1dO'      Ò;\82¿I2N°\1c©5\92$KÆi\8aà¼i\96\8bÃ\1f\9c¾)     \18\8eGkbÓ\10vS\0A\83ÅÒd\9c\19F§þ\ 5o%\89t\9cÃo©]\92t:\9eÂo©\80Ô&\r\9dÖ¤\12¥ÂÒH7\8c®ãùD\\9bÂ\ fÄ,i®\ 6\0*\99\8a³t\92\ 2\84T<ͦ9Ä\87d\92\8eÃ\ 3hcã$A§\0<\ 5à9\96ÄM4\95fQ\13©4qÀx\8aõ\16àM\8a\8e³).\r³ÏÅi:M¡~L<\99\ 2 i\92\81&&  Md*\9efȤ7M\ 1ý4 E¯\ 2©I\92¡a\9cé8Å¡7\93\\9cå \17ÃÄÓi\f\8b â\1c\rÏÒ\1c\15ç\98t\1a¿H¤â$\87\1aY"N£FhJÆSÀ\1cx\15^H2À\fx!\95b\18o\9a\ 6Â(\ 6¿I¥SÐÈBc
+\b¢9Ô\8feâ)\8ea¡    xL\13)ÄG \87H\92\18\18A\91øM\86\8d\ 3oq\13I%½¸\81I\ 2\ 4ÜÂ0RK\92\ 6
+M\0´\0¡\ 4!õI¥ÓX$\80ëTZ\82\8dç\ 1M[<Ťi©)\89_\ 4Z`\82\19\14\13'\92\f©\87\95JÆY\86\18¡\89Fs¤Q\ 5-\14\99ÖS\9e\ 2V&\93\8caxt\12È¢%.P0UÐ\r\ 4\85¢\81£\0\80a)\84\ fd\ 2ä1M³è\7fè-\12\1e¡\96\14\87ÿ\ f\rÀL\98\96$f\ 4¼\0ÔÃß\1c0\9bÅo\900\ 1è\ 5`\fzN !gñ¯ =è\ 1 Pº\82\86$j\87¿P·4AâÇð&L3É »CÊÄ\90\Rn\ 2ñ¤I\18:\8c:Îby\ 5\9esHªI\10æ$C\81´²é8ä±V"\9a¸\14Í@#\rò\9a¤\116<v\80\ 5\12F\80jz\9b\1eÜH3lZk¬!ùOI\80Ì\8dé4È\94¡\11\ 6J¦HZÂ\9dJ"µXÒÅ¿°ÖJÿ\f\10i`'\90l\924Ìy\12©ªÚD\ 3\ e\02ôàq¦\f\rHY\90\$©8\9166é{qxv\96[dlòkð«±\rÐ%\91µ@\93µÔ¦ïg$~\bc\83\89\83YJ¥5´Ø
+³òË\1a)Z\eØ\ 4\ 4\ 5·QË\7f&\11ÅÒ\væ¿(Vý\8b\ 2e°n!ô\18ÓÒ°,Ú´ai#°jSG\80Æ
+¶1\95¢\rÓ§µé\aÂÉX¬Út<Áª²Ü {\v&<M\98 «m:zÍ\94Iô2\1cÖA\1dµr\v\86ÆH\9ccÐR\91´nÓ\91\96\96\19lѤ\7f\93\85Õ\85´iÓÑk¤\fQ\e^H\10\11p=Å áHäõx¹´ÔKkBË\85QÐ)Pî¤\ e\14n¢q'\8aÀdã\16I\9f\f\91²%¢0ka\rÆð\10¸\14VDD+\97\94¸\8bͪ\f\f¿*÷\19\9a\ 3¿ÃK:^\ 59Ò \j\93n¤`pÌ\7f\9dÄÞ\82u\936"3&<"ä\rèû\8dtM:|°Þ\9b)R\9a 'ú\13tÖü\12xG\ 69\87Å
+p G\81\94\94Bîd\9cB\ 4\89\e\r\17ÅJk\83¾Mß\8d4\8dY\96¯$R\7fìÉ \83\ eë\ 6\9a5\1a\89'\89\1c\v\12Ò,¥°3F\9bÛH2Åj/£FpF¸48#\86Æ\14rc8D&ø\80©\94$\v\80\ 6¯\12ÆF\ 6<\13\f¯/Q©\89\
\1c!\99M\8a¢$±\ 3g\92N\ 1 à§qiN\12Ú\14        Ä&Í\8dæ·uò\17Ã\a\98ÐÊOÒ\80\81\ 5\96Òþ®y\82\97!oXí\86ü?\86ÕºÉ\7f+ÝHÉS½\82\90wÍÄ\19\82£õï\ 1Ù°ä\13\ 4­\7fYߨ"Ö¿nÙ¨¾þ)±9Í!ÇÑ\80\8a\ 2\87\14\19_\ 3*µQ\83ª{ݲÑ\80*\85\97à\94     \15\a\9e\1eM\99\8d:¨Úë\96\8dFTà,¦\88¤\11U
+¬4\b\8b\11\95Ö¨\87ª¾nÙhD\ 5Ö\v\ 6Tà"\82L\99\8dz¨êë\96\8d:Tà\13\81YPã<0K\14\9c\19³\1c·\18\8d\1a\12Ýë\96\8dêë|\e¤2x7\1e·F½®÷Kluûè,\1e ñ*¡ÆÀÒÿÑOþË\ 3Î4xu\fþ3\ 6\83\ 6\8f\ fûÝ
+\15\f)!|\1cyÒØ1C­\86ÎHmh­#ßq\r\93·\85©\e\9c\ e.â+Ïc½3\84Ñz\85\ 1¾³)³\12Ê\8dF%\ 4[\9eJ\9aõͲQ}ݨ\84zTª¾éQ©\8d\1aTÝë\96\8d\ 6T\9aÂèQ©ú¦G¥6ê j¯[6\1a
+£C¥é\9b\ e\95Ö¨\87ª¾nÙhD¥*\8c\1e\95ªozTj£\1eªúºe£\ e\95\83\12ê1«ú¦Ç¬6jHt¯[6ª¯ï^        \91\82#\84+\95PéèB      Õ®n\94P\a×V        aY\8f³I\1a¨ hÐ19^\ 2|,\89òQJcÍÐ\ba\17ÐX3¼mÕ¦¾üi\9d¡\vÆÀ¡¢É\14\97\fy\13\8d¹Ø\1f\7fy\83<\9fït\16£\9bɼ\85úêrtØ\89`Ác5\11\v\81\1c\99¦MĪ\8d*aº·­ÚvN,¸RÒü\1a\88%@çQÒÈ@¬Ú¨\11¦½mÕ¶{b\93ñ\14\8cÄÂLB¸C\1a\89Õ\1au\84©o[µí\9eXpXÓ\1cc"\96\82\9d\e\88U\eu\84©o[µí\98X³9#!\ 2cÀ»7ÑNÄ\19\92N\9ahW\eU:uo[µ©/Û\183Z³e1Ùl\80Uc\92i:N¦QB\v~\ 5ãÁ\82ÿ\ fö-\ 6n<Ç&%c\84Í\vÊ\©d¡|,"\ 1Ì[\fB\88\14Ì6K\eú\82'ÎH\80\95¾`\89b°l&S\1c¹\ 2*o\v\15çá¨T\8aÖC\95íÛ\963\96пéM\Næ7½ÎDì\ 2\ fÑãU<KÜôZÃ\8b\16\17ôö\ 6\vù³²ÌúÛÏ\898\92\1eÉÂá\ræ»\93vï=\7fÆ¡Ý\88ÆüÏ°÷®á7\88\10é}ì¢9¥\9cçÔ´>a\8e0Þ`ÈûøàhùI"Nr´Éò+\8dFËÏàÈÖhå-Ú´\97wnù\rÄ*FÞ@¬jùUÂtVÞ¢m÷ĪvÚ@¬bä\rĪ\96_#L³ò\16mÿ\ 6b\15;­'V5òzb5˯#Lµò\16mÿ\ 6b\15;m V1ò\ 6bU˯#Lµò\16m»&ÖÞò\ehW\8c¼\81vÕò«tꬼE\9böòÿ        Ë\8f\17\1a Á\8dåWú®¶üjO\17\96_\aõÿ[þ\15\96\80¿\97\8c\91I»¿#é/\96å ôàÐÎ,H\13HTÊËJyci\97\1dí\0\12\1c\8c\9fãÔÇ$\93Ö½\8dþÒmc£¿Òd\9c`ðþ±ò*GQ*dùw´      ­ V\1ec*Õ·u4wÔü#Þ\91¦A\82H)wJB\0E¤Y­\91\84¸9\ e3\ 5\96\80eâiÚؤÛo\97\9b \86úßÓ33\ 5M\rÃÍ2\a\r\14[\80f¨!óíP\1e\1d\v4\12¡\ 4Xÿé\19\83\11\ 6Á\85\90çÛaBpGÁÍB8\1dÅwÉ\90¡Q\1f'Èr    ×¼\14ðª\ 6]]^UÕ\80ÄôÔ\90¢ÄÌ\9cÔ"ÞôâIJT\85ļ<P\ 2O-\0Ê\0\93LjqI~QªBqF~9H\ 4¨\ 5¦\UÕÕß\8d\17\0¨K.\ 5\rendstream\rendobj\r454 0 obj\r<</CreationDate(D:20090603145654-07'00')/Creator(Adobe Illustrator CS3)/ModDate(D:20090604104953-07'00')>>\rendobj\rxref\r0 459\r0000000003 65535 f\r
+0000000016 00000 n\r
+0000026058 00000 n\r
+0000000004 00000 f\r
+0000000006 00000 f\r
+0000028981 00000 n\r
+0000000007 00000 f\r
+0000000008 00000 f\r
+0000000009 00000 f\r
+0000000010 00000 f\r
+0000000011 00000 f\r
+0000000012 00000 f\r
+0000000013 00000 f\r
+0000000014 00000 f\r
+0000000018 00000 f\r
+0000026109 00000 n\r
+0000028838 00000 n\r
+0000028869 00000 n\r
+0000000019 00000 f\r
+0000000020 00000 f\r
+0000000021 00000 f\r
+0000000022 00000 f\r
+0000000026 00000 f\r
+0000026180 00000 n\r
+0000028722 00000 n\r
+0000028753 00000 n\r
+0000000027 00000 f\r
+0000000028 00000 f\r
+0000000029 00000 f\r
+0000000030 00000 f\r
+0000000031 00000 f\r
+0000000032 00000 f\r
+0000000033 00000 f\r
+0000000034 00000 f\r
+0000000035 00000 f\r
+0000000036 00000 f\r
+0000000037 00000 f\r
+0000000038 00000 f\r
+0000000039 00000 f\r
+0000000040 00000 f\r
+0000000044 00000 f\r
+0000026251 00000 n\r
+0000028606 00000 n\r
+0000028637 00000 n\r
+0000000045 00000 f\r
+0000000046 00000 f\r
+0000000047 00000 f\r
+0000000048 00000 f\r
+0000000052 00000 f\r
+0000026322 00000 n\r
+0000028490 00000 n\r
+0000028521 00000 n\r
+0000000053 00000 f\r
+0000000054 00000 f\r
+0000000055 00000 f\r
+0000000056 00000 f\r
+0000000057 00000 f\r
+0000000058 00000 f\r
+0000000059 00000 f\r
+0000000060 00000 f\r
+0000000061 00000 f\r
+0000000062 00000 f\r
+0000000063 00000 f\r
+0000000064 00000 f\r
+0000000065 00000 f\r
+0000000066 00000 f\r
+0000000070 00000 f\r
+0000026393 00000 n\r
+0000028374 00000 n\r
+0000028405 00000 n\r
+0000000071 00000 f\r
+0000000072 00000 f\r
+0000000073 00000 f\r
+0000000074 00000 f\r
+0000000078 00000 f\r
+0000026464 00000 n\r
+0000028258 00000 n\r
+0000028289 00000 n\r
+0000000079 00000 f\r
+0000000080 00000 f\r
+0000000081 00000 f\r
+0000000082 00000 f\r
+0000000083 00000 f\r
+0000000084 00000 f\r
+0000000085 00000 f\r
+0000000086 00000 f\r
+0000000087 00000 f\r
+0000000088 00000 f\r
+0000000089 00000 f\r
+0000000090 00000 f\r
+0000000091 00000 f\r
+0000000092 00000 f\r
+0000000096 00000 f\r
+0000026535 00000 n\r
+0000028142 00000 n\r
+0000028173 00000 n\r
+0000000097 00000 f\r
+0000000098 00000 f\r
+0000000099 00000 f\r
+0000000103 00000 f\r
+0000026606 00000 n\r
+0000028024 00000 n\r
+0000028056 00000 n\r
+0000000104 00000 f\r
+0000000105 00000 f\r
+0000000106 00000 f\r
+0000000107 00000 f\r
+0000000108 00000 f\r
+0000000109 00000 f\r
+0000000110 00000 f\r
+0000000111 00000 f\r
+0000000112 00000 f\r
+0000000113 00000 f\r
+0000000114 00000 f\r
+0000000115 00000 f\r
+0000000116 00000 f\r
+0000000117 00000 f\r
+0000000118 00000 f\r
+0000000122 00000 f\r
+0000026680 00000 n\r
+0000027906 00000 n\r
+0000027938 00000 n\r
+0000000123 00000 f\r
+0000000124 00000 f\r
+0000000125 00000 f\r
+0000000129 00000 f\r
+0000026754 00000 n\r
+0000027788 00000 n\r
+0000027820 00000 n\r
+0000000130 00000 f\r
+0000000131 00000 f\r
+0000000132 00000 f\r
+0000000133 00000 f\r
+0000000134 00000 f\r
+0000000135 00000 f\r
+0000000136 00000 f\r
+0000000137 00000 f\r
+0000000138 00000 f\r
+0000000139 00000 f\r
+0000000140 00000 f\r
+0000000141 00000 f\r
+0000000142 00000 f\r
+0000000143 00000 f\r
+0000000144 00000 f\r
+0000000145 00000 f\r
+0000000146 00000 f\r
+0000000147 00000 f\r
+0000000148 00000 f\r
+0000000149 00000 f\r
+0000000150 00000 f\r
+0000000151 00000 f\r
+0000000152 00000 f\r
+0000000153 00000 f\r
+0000000154 00000 f\r
+0000000155 00000 f\r
+0000000156 00000 f\r
+0000000157 00000 f\r
+0000000158 00000 f\r
+0000000159 00000 f\r
+0000000160 00000 f\r
+0000000161 00000 f\r
+0000000162 00000 f\r
+0000000163 00000 f\r
+0000000164 00000 f\r
+0000000165 00000 f\r
+0000000166 00000 f\r
+0000000167 00000 f\r
+0000000168 00000 f\r
+0000000169 00000 f\r
+0000000170 00000 f\r
+0000000171 00000 f\r
+0000000172 00000 f\r
+0000000173 00000 f\r
+0000000174 00000 f\r
+0000000175 00000 f\r
+0000000176 00000 f\r
+0000000177 00000 f\r
+0000000178 00000 f\r
+0000000179 00000 f\r
+0000000183 00000 f\r
+0000026828 00000 n\r
+0000027670 00000 n\r
+0000027702 00000 n\r
+0000000184 00000 f\r
+0000000185 00000 f\r
+0000000186 00000 f\r
+0000000187 00000 f\r
+0000000188 00000 f\r
+0000000189 00000 f\r
+0000000190 00000 f\r
+0000000191 00000 f\r
+0000000192 00000 f\r
+0000000193 00000 f\r
+0000000194 00000 f\r
+0000000195 00000 f\r
+0000000196 00000 f\r
+0000000197 00000 f\r
+0000000198 00000 f\r
+0000000199 00000 f\r
+0000000200 00000 f\r
+0000000201 00000 f\r
+0000000202 00000 f\r
+0000000203 00000 f\r
+0000000204 00000 f\r
+0000000205 00000 f\r
+0000000206 00000 f\r
+0000000207 00000 f\r
+0000000208 00000 f\r
+0000000209 00000 f\r
+0000000210 00000 f\r
+0000000211 00000 f\r
+0000000212 00000 f\r
+0000000213 00000 f\r
+0000000214 00000 f\r
+0000000215 00000 f\r
+0000000216 00000 f\r
+0000000217 00000 f\r
+0000000218 00000 f\r
+0000000219 00000 f\r
+0000000220 00000 f\r
+0000000221 00000 f\r
+0000000222 00000 f\r
+0000000223 00000 f\r
+0000000224 00000 f\r
+0000000225 00000 f\r
+0000000226 00000 f\r
+0000000227 00000 f\r
+0000000228 00000 f\r
+0000000229 00000 f\r
+0000000230 00000 f\r
+0000000231 00000 f\r
+0000000232 00000 f\r
+0000000233 00000 f\r
+0000000237 00000 f\r
+0000026902 00000 n\r
+0000027552 00000 n\r
+0000027584 00000 n\r
+0000000238 00000 f\r
+0000000239 00000 f\r
+0000000240 00000 f\r
+0000000241 00000 f\r
+0000000242 00000 f\r
+0000000243 00000 f\r
+0000000244 00000 f\r
+0000000245 00000 f\r
+0000000246 00000 f\r
+0000000247 00000 f\r
+0000000248 00000 f\r
+0000000249 00000 f\r
+0000000250 00000 f\r
+0000000251 00000 f\r
+0000000252 00000 f\r
+0000000253 00000 f\r
+0000000254 00000 f\r
+0000000255 00000 f\r
+0000000256 00000 f\r
+0000000257 00000 f\r
+0000000258 00000 f\r
+0000000259 00000 f\r
+0000000260 00000 f\r
+0000000261 00000 f\r
+0000000262 00000 f\r
+0000000263 00000 f\r
+0000000264 00000 f\r
+0000000265 00000 f\r
+0000000266 00000 f\r
+0000000267 00000 f\r
+0000000268 00000 f\r
+0000000269 00000 f\r
+0000000270 00000 f\r
+0000000271 00000 f\r
+0000000272 00000 f\r
+0000000273 00000 f\r
+0000000274 00000 f\r
+0000000275 00000 f\r
+0000000276 00000 f\r
+0000000277 00000 f\r
+0000000278 00000 f\r
+0000000279 00000 f\r
+0000000280 00000 f\r
+0000000281 00000 f\r
+0000000282 00000 f\r
+0000000283 00000 f\r
+0000000284 00000 f\r
+0000000285 00000 f\r
+0000000286 00000 f\r
+0000000287 00000 f\r
+0000000288 00000 f\r
+0000000289 00000 f\r
+0000000290 00000 f\r
+0000000291 00000 f\r
+0000000295 00000 f\r
+0000026976 00000 n\r
+0000027434 00000 n\r
+0000027466 00000 n\r
+0000000296 00000 f\r
+0000000297 00000 f\r
+0000000298 00000 f\r
+0000000299 00000 f\r
+0000000300 00000 f\r
+0000000301 00000 f\r
+0000000302 00000 f\r
+0000000303 00000 f\r
+0000000304 00000 f\r
+0000000305 00000 f\r
+0000000306 00000 f\r
+0000000307 00000 f\r
+0000000308 00000 f\r
+0000000309 00000 f\r
+0000000310 00000 f\r
+0000000311 00000 f\r
+0000000312 00000 f\r
+0000000313 00000 f\r
+0000000314 00000 f\r
+0000000315 00000 f\r
+0000000316 00000 f\r
+0000000317 00000 f\r
+0000000318 00000 f\r
+0000000319 00000 f\r
+0000000320 00000 f\r
+0000000321 00000 f\r
+0000000322 00000 f\r
+0000000323 00000 f\r
+0000000324 00000 f\r
+0000000325 00000 f\r
+0000000326 00000 f\r
+0000000327 00000 f\r
+0000000328 00000 f\r
+0000000329 00000 f\r
+0000000330 00000 f\r
+0000000331 00000 f\r
+0000000332 00000 f\r
+0000000333 00000 f\r
+0000000334 00000 f\r
+0000000335 00000 f\r
+0000000336 00000 f\r
+0000000337 00000 f\r
+0000000338 00000 f\r
+0000000339 00000 f\r
+0000000340 00000 f\r
+0000000341 00000 f\r
+0000000342 00000 f\r
+0000000343 00000 f\r
+0000000344 00000 f\r
+0000000345 00000 f\r
+0000000346 00000 f\r
+0000000347 00000 f\r
+0000000348 00000 f\r
+0000000349 00000 f\r
+0000000353 00001 f\r
+0000027050 00000 n\r
+0000027316 00000 n\r
+0000027348 00000 n\r
+0000000354 00000 f\r
+0000000355 00000 f\r
+0000000356 00000 f\r
+0000000357 00000 f\r
+0000000358 00000 f\r
+0000000359 00000 f\r
+0000000360 00000 f\r
+0000000361 00000 f\r
+0000000362 00000 f\r
+0000000363 00000 f\r
+0000000364 00000 f\r
+0000000365 00000 f\r
+0000000366 00000 f\r
+0000000367 00000 f\r
+0000000368 00000 f\r
+0000000369 00000 f\r
+0000000370 00000 f\r
+0000000371 00000 f\r
+0000000372 00000 f\r
+0000000373 00000 f\r
+0000000374 00000 f\r
+0000000375 00000 f\r
+0000000376 00000 f\r
+0000000377 00000 f\r
+0000000378 00000 f\r
+0000000379 00000 f\r
+0000000380 00000 f\r
+0000000381 00000 f\r
+0000000382 00000 f\r
+0000000383 00000 f\r
+0000000384 00000 f\r
+0000000385 00000 f\r
+0000000386 00000 f\r
+0000000387 00000 f\r
+0000000388 00000 f\r
+0000000389 00000 f\r
+0000000390 00000 f\r
+0000000391 00000 f\r
+0000000392 00000 f\r
+0000000393 00000 f\r
+0000000394 00000 f\r
+0000000395 00000 f\r
+0000000396 00000 f\r
+0000000397 00001 f\r
+0000000398 00000 f\r
+0000000399 00000 f\r
+0000000400 00000 f\r
+0000000406 00000 f\r
+0000034768 00000 n\r
+0000034844 00000 n\r
+0000035022 00000 n\r
+0000035933 00000 n\r
+0000052842 00000 n\r
+0000000411 00001 f\r
+0000028954 00000 n\r
+0000027124 00000 n\r
+0000027198 00000 n\r
+0000027230 00000 n\r
+0000000412 00001 f\r
+0000000413 00001 f\r
+0000000415 00001 f\r
+0000034140 00000 n\r
+0000000417 00001 f\r
+0000031078 00000 n\r
+0000000426 00001 f\r
+0000032832 00000 n\r
+0000032895 00000 n\r
+0000033125 00000 n\r
+0000033180 00000 n\r
+0000033818 00000 n\r
+0000033964 00000 n\r
+0000034061 00000 n\r
+0000031306 00000 n\r
+0000000427 00001 f\r
+0000000429 00001 f\r
+0000033754 00000 n\r
+0000000430 00001 f\r
+0000000432 00001 f\r
+0000031673 00000 n\r
+0000000433 00001 f\r
+0000000435 00001 f\r
+0000033690 00000 n\r
+0000000436 00001 f\r
+0000000442 00001 f\r
+0000033263 00000 n\r
+0000033409 00000 n\r
+0000033530 00000 n\r
+0000033611 00000 n\r
+0000032040 00000 n\r
+0000000443 00001 f\r
+0000000445 00001 f\r
+0000032768 00000 n\r
+0000000446 00001 f\r
+0000000449 00001 f\r
+0000032404 00000 n\r
+0000031192 00000 n\r
+0000000450 00001 f\r
+0000000451 00001 f\r
+0000000000 00001 f\r
+0000029401 00000 n\r
+0000030659 00000 n\r
+0000076660 00000 n\r
+0000034204 00000 n\r
+0000034254 00000 n\r
+0000030726 00000 n\r
+0000000367 00000 n\r
+trailer\r<</Size 459/Root 1 0 R/Info 454 0 R/ID[<A3DACB2CAA994ADF839A177E1EF222F1><94FD791731084F1087F9FE9BDDF38204>]>>\rstartxref\r76784\r%%EOF\r
\ No newline at end of file
diff --git a/doc/gfx_and_css/logo.pdf b/doc/gfx_and_css/logo.pdf
new file mode 100644 (file)
index 0000000..593dca4
--- /dev/null
@@ -0,0 +1,201 @@
+%PDF-1.4\r%âãÏÓ\r
+1 0 obj\r<</Metadata 50 0 R/Pages 2 0 R/Type/Catalog>>\rendobj\r50 0 obj\r<</Subtype/XML/Length 26031/Type/Metadata>>stream\r
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.1-c036 46.277092, Fri Feb 23 2007 14:16:18        ">
+   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+      <rdf:Description rdf:about=""
+            xmlns:dc="http://purl.org/dc/elements/1.1/">
+         <dc:format>application/pdf</dc:format>
+         <dc:title>
+            <rdf:Alt>
+               <rdf:li xml:lang="x-default">Netatalk_Logo</rdf:li>
+            </rdf:Alt>
+         </dc:title>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xap="http://ns.adobe.com/xap/1.0/"
+            xmlns:xapGImg="http://ns.adobe.com/xap/1.0/g/img/">
+         <xap:CreatorTool>Adobe Illustrator CS3</xap:CreatorTool>
+         <xap:CreateDate>2009-06-04T10:50:16-07:00</xap:CreateDate>
+         <xap:ModifyDate>2009-06-04T10:50:16-07:00</xap:ModifyDate>
+         <xap:MetadataDate>2009-06-04T10:50:16-07:00</xap:MetadataDate>
+         <xap:Thumbnails>
+            <rdf:Alt>
+               <rdf:li rdf:parseType="Resource">
+                  <xapGImg:width>256</xapGImg:width>
+                  <xapGImg:height>256</xapGImg:height>
+                  <xapGImg:format>JPEG</xapGImg:format>
+                  <xapGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FUm8y+cvKnle1F15h1a10uEglPrMqoz06iNCebn2UHFXjHmr/nMz8u9NLxaBY3mvTLXjJQW&#xA;du3+zlDS/wDJLFXlHmH/AJzM/M2/LJpFnp+jwn7DLG1zOPm8remf+ReKvP8AV/z5/OLVSTdebNQT&#xA;l1FpILMda9LYQ4qxW98z+Zb5uV7q17dMepmuJZD0p+0x7YqlmKuxVM7LzP5lsW5WWrXtqw6GG4lj&#xA;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&#xA;REf5NWzf9LVx/wA8R/zXiqKsvyMtbi/trU6u6idbpi/oA0+rWU92Nuf7Rt+P01xVkXl7/nGOx1a/&#xA;8n2reYJYR5o0FtckcWyt6DKts3ogeoOY/wBK+1t06Yqm1j/ziPp1z581XyufMsyx6bYWd8t19UUl&#xA;zdyTIUKertx9DrXvirtf/wCcR9O0rzR5X0RfMs0q+Yri7gec2iqYRa2cl0CF9U8uRi49RirIv+hH&#xA;NK/6m6f/AKQk/wCq2Ku/6Ec0r/qbp/8ApCT/AKrYq7/oRzSv+pun/wCkJP8Aqtirv+hHNK/6m6f/&#xA;AKQk/wCq2Ku/6Ec0r/qbp/8ApCT/AKrYq7/oRzSv+pun/wCkJP8Aqtirv+hHNK/6m6f/AKQk/wCq&#xA;2Ku/6Ec0r/qbp/8ApCT/AKrYq7/oRzSv+pun/wCkJP8Aqtirv+hHNK/6m6f/AKQk/wCq2Ku/6Ec0&#xA;r/qbp/8ApCT/AKrYqyeL/nFWwSJEPmOZiqhS31Vd6Clf73FV/wD0Kxp//UxS/wDSMv8A1UxV3/Qr&#xA;Gn/9TFL/ANIy/wDVTFXyZ+alhZ6Z+YGtaTZ3RvLfTLg2S3DKELPAOEvwgtSkoYdcVeo/84Z+Xjf/&#xA;AJm3mrutYdH0+RlfwnuWWJB9MfqYq9X/AOczPKp1L8u7HX4k5TaDeD1Gp9m3vAIn/wCSqxYq+LUd&#xA;kdXU0ZSCp9xir1GyukurSG4XpKgb5EjcfQcVV8VbUVOKpP5k0xbqW3Bmkj4K32DTqR/TFUtj8sxN&#xA;/wAflwP9kP6Yqio/KMLf8f1yPk4/piqKj8kwt/0sbsfJx/TFUVH5Cgb/AKWd4Pk4/piqLi/Lm3b/&#xA;AKW18PlIP6Yqio/yxtm/6XGoD5SD+mKo3T/yntJtTtLc63qSCZbwl1lAYehp9zcCm37Rh4t/kk4q&#xA;ynyt+RFjqOp+RLdvMusQDXvLT6tI8U6hrdglofQg+H4Yv3/T2GKp5p3/ADjlp0/5la1oJ82a6kdl&#xA;pljdreLcKJ3NxLcIUduO6J6NVHucVd5n/wCcctO0/wA5eTdKXzZrsy61c3sT3EtwplgEFjLcBoTx&#xA;+EsY+Lf5JxVlX/QqWlf9Tt5k/wCkpP8AmjFXf9CpaV/1O3mT/pKT/mjFXf8AQqWlf9Tt5k/6Sk/5&#xA;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</xapGImg:image>
+               </rdf:li>
+            </rdf:Alt>
+         </xap:Thumbnails>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/"
+            xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
+         <xapMM:DocumentID>uuid:94E82CBF528711DE830DC7B65C12678A</xapMM:DocumentID>
+         <xapMM:InstanceID>uuid:a8158099-b802-4d00-acfd-b4ab575a94be</xapMM:InstanceID>
+         <xapMM:DerivedFrom rdf:parseType="Resource">
+            <stRef:instanceID>uuid:94E82CBE528711DE830DC7B65C12678A</stRef:instanceID>
+            <stRef:documentID>uuid:1B95FEC551E111DEA13AAE68EE5F3A4D</stRef:documentID>
+         </xapMM:DerivedFrom>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xapTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+            xmlns:xapG="http://ns.adobe.com/xap/1.0/g/">
+         <xapTPg:NPages>1</xapTPg:NPages>
+         <xapTPg:HasVisibleTransparency>True</xapTPg:HasVisibleTransparency>
+         <xapTPg:HasVisibleOverprint>False</xapTPg:HasVisibleOverprint>
+         <xapTPg:MaxPageSize rdf:parseType="Resource">
+            <stDim:w>3.000000</stDim:w>
+            <stDim:h>3.000000</stDim:h>
+            <stDim:unit>Inches</stDim:unit>
+         </xapTPg:MaxPageSize>
+         <xapTPg:PlateNames>
+            <rdf:Seq>
+               <rdf:li>Black</rdf:li>
+            </rdf:Seq>
+         </xapTPg:PlateNames>
+         <xapTPg:SwatchGroups>
+            <rdf:Seq>
+               <rdf:li rdf:parseType="Resource">
+                  <xapG:groupName>Default Swatch Group</xapG:groupName>
+                  <xapG:groupType>0</xapG:groupType>
+               </rdf:li>
+            </rdf:Seq>
+         </xapTPg:SwatchGroups>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+         <pdf:Producer>Adobe PDF library 8.00</pdf:Producer>
+      </rdf:Description>
+   </rdf:RDF>
+</x:xmpmeta>
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                           
+<?xpacket end="w"?>\rendstream\rendobj\r2 0 obj\r<</Count 1/Type/Pages/Kids[5 0 R]>>\rendobj\r5 0 obj\r<</Parent 2 0 R/Contents 47 0 R/BleedBox[0.0 0.0 216.0 216.0]/ArtBox[16.0 18.25 200.0 202.25]/Group 48 0 R/MediaBox[0.0 0.0 216.0 216.0]/TrimBox[0.0 0.0 216.0 216.0]/Resources<</XObject<</Fm0 20 0 R/Fm1 26 0 R/Fm2 36 0 R/Fm3 42 0 R>>/Properties<</MC0<</Color[65535 20224 20224]/Visible true/Editable true/Dimmed false/Preview true/Printed true/Title(Layer 2)>>>>/ExtGState<</GS0 11 0 R/GS1 43 0 R>>>>/Type/Page>>\rendobj\r47 0 obj\r<</Length 1191/Filter/FlateDecode>>stream\r
+H\89\94\8eÝ6\fÝû+ô\ 3Ö\88¢\1eÔ¶IÛM³\bºèº\18$-ÐL\8bI\81\ 2ùû\1eR¶,ûÞ;E1\98±)¾\ e_2çé§_¿}úê\9e\vî»÷ïÜòº\ 4\17©Øïª\7f¾~Z~q\7fâÔ~|åìþX\9e~ü9¸ßþ^^\1dÙ99
+â¨\89\17\ eä\9e_LþeY\93ø\16Uf\15ñ¹6·ró%ËAëSÜó2\ e\88«Ï0²ë®T«§ÜÔÈþú¼\\99Wí«ù\8bû\81K\7f\9e\97ÏËÇ-BBtST¾&\8e®D/UÚ\14\19ù\84\90\93\8f\11\89*\90* rV\ 4F\14Ï\924.
+¾      ;*>\17\0h8o\8e\19T\85pó"Ñ¥âc5áê\13Þrö\89\18\ 6Cv\82¿A\91'_[r\ 4{A3°rð9%'\b\11yÈ®
+t`8±'©®Àk²ôæ\80\83âjô­"o¹y\ 2Ê\9a})\11\ 1ÀHr\9aË\14U\1a´Ä¬\a\11.Ö"\9e\82ñ#\8c*ÉE\94d&\15¯Á\97Äz ¶Õ\a\99²\14\aÕNæ.\8d yâ7_CÝ\95\85\90.\9alK\ 4\862|\83Ì1\rd »ô\ 6¼A\9dDãJAó\e\82\1a\0jò@ÃwcW\92çjæ)"qªÑk¸\12J\12\11KSE£\93oРBT8P\95\1cÌ\b|\17ëA-\rTrÚè\98\8c\9fòÐàbFS0· Åh\12\930\v\82ºË@\95È\ eP>Ö0Р­FÌ_й$´/c\86Ð}\9b4R(ÚíH¬ñ{Ô@â\ 5Ãðm±£Xó8úb\8d\19j\9a\8c¹L\a½Ç×ÞäÚ÷ÿL\93\12N\93\121Whè\86\19\8f1   \8eÉ£\91¾,\ 5W\ 3\ f\8aì\89n?\88ÁB\a\v_É ¯\98$ªöZÌ\e¥ñª\87¿\eº\ 3SF/d\81\9b\98Íù@\85\11eäÂlöWL0\95\ 2\1aÞR¼!\91\11\ 5\ f\ ed;@a5gWºÇ¸Eò\85Ø\ 3\rÇë5\10\fTÎé^v\11Y\10Í\ 2\8a\fWzd\11Í\9bò\95\1cÒ¢Çgê^B   \ 5\ 3ë\ 1\fînµDWzö{K\ eiÜ2å\86¼\v$!#øædÓ\9f/eíª\88«Ã\9cÇ©50ÈFé\939©4®\ 2hcÞ\e\93©\r²©­]\1aå±\16\9aieg_s÷¤¦\ 6ÉgÝ\eø\99\røãi9Ï@§Ê)igên\92
\19þÿ\9f\17į¡¨å£N:Üå \93\86Ù{Á\98\9a°Ð\aYS\18\ e\95â\18â\e\94¸¡©\84èìâ\8dq.'¾¤¡\ f\ 5%\f[\99\ e´¬(\9b~\82#\YUõ.n\ eµ\95~;Ô2\b´K\1e¢V5ª<Ñè\10]!ô»T{ófû\88\8c\83\8b\81\1e\v\82/2q61|ZbÃäáº\15Ý\9e>/\r\8c&C\0V
+>¦\93\80æ@«8$Ø\17|þO\12\v\f\ 1Ât׳@Ñì\1d\12°ØN\12¯ºµ\91nmO?¼\ 4÷þ¯\19:V       äé\rè]à-è\9bÄcè\9bÀ\eÐ7\89·¡S\87N\rÝ\81*`=j\ 1\1a\14"«ÿXë\ 6\1e_E`Ù$\14z>ó\11}\eü\ eüÄ',i´ó;î\99/ØåÚÎî gö     u<£ÆvAú\81~\8cz\93x\88zã?D½ñ\1f¡ÞØÿ\81\9a;껫±-üÀ¢ËÓ´ðcci}áÇ`\ 2Ç\8a\85¼Ö\83´§­jû\89Ö½aûÜuWÂ~Y#Û¿½báWf<N®Ú7öÏþ7õ}áWK\9bä\8b\11:7\84\r\v«\9d\90ý_Q\8c\e\8e×¾DËÄ\gÍu²©\8b((Ýò3\9e]­ú\82¥-lÏçesÕÉIüdG/\98ï?à\1f³\8fË¿\ 2\f\0~ĨÇ\rendstream\rendobj\r48 0 obj\r<</I false/K false/CS/DeviceCMYK/S/Transparency>>\rendobj\r11 0 obj\r<</OPM 1/BM/Normal/CA 1.0/OP false/SMask/None/ca 1.0/AIS false/op false/Type/ExtGState/SA true>>\rendobj\r43 0 obj\r<</OPM 1/BM/Normal/CA 0.5/OP false/SMask/None/ca 0.5/AIS false/op false/Type/ExtGState/SA true>>\rendobj\r20 0 obj\r<</Subtype/Form/Length 129/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 9 0 R/Resources<</Shading<</Sh0 17 0 R>>/ColorSpace<</CS0 13 0 R>>/ExtGState<</GS0 11 0 R>>>>/BBox[106.997 139.145 150.43 135.867]>>stream\r
+q
+150.43 135.867 -43.433 3.278 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+43.4326172 0 0 -43.4326172 106.9970703 137.5058594 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r26 0 obj\r<</Subtype/Form/Length 129/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 23 0 R/Resources<</Shading<</Sh0 17 0 R>>/ColorSpace<</CS0 13 0 R>>/ExtGState<</GS0 11 0 R>>>>/BBox[106.997 133.854 150.43 130.576]>>stream\r
+q
+150.43 130.576 -43.433 3.278 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+43.4326172 0 0 -43.4326172 106.9970703 132.2148438 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r36 0 obj\r<</Subtype/Form/Length 126/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 29 0 R/Resources<</Shading<</Sh0 32 0 R>>/ColorSpace<</CS0 13 0 R>>/ExtGState<</GS0 11 0 R>>>>/BBox[39.6411 84.9033 88.6143 81.626]>>stream\r
+q
+39.641 84.903 48.973 -3.277 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+-48.9736328 0 0 48.9736328 88.6142578 83.2646484 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r42 0 obj\r<</Subtype/Form/Length 126/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Group 39 0 R/Resources<</Shading<</Sh0 32 0 R>>/ColorSpace<</CS0 13 0 R>>/ExtGState<</GS0 11 0 R>>>>/BBox[39.6411 90.1943 88.6143 86.917]>>stream\r
+q
+39.641 90.194 48.973 -3.277 re
+W n
+q
+0 g
+1 i 
+/GS0 gs
+-48.9736328 0 0 48.9736328 88.6142578 88.5556641 cm
+BX /Sh0 sh EX Q
+Q
+\rendstream\rendobj\r39 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r13 0 obj\r[/DeviceN[/Black]/DeviceCMYK 14 0 R 15 0 R]\rendobj\r14 0 obj\r<</Length 91/FunctionType 4/Filter/FlateDecode/Domain[0.0 1.0]/Range[0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]>>stream\r
+H\89ª6Ô3\0\ 3\ 5#\ 5C\85¢ü\9c\1c\ 5bD\f\142óRR+\102\ÉeE
\15É\19
+Å¥I\b
+ºèf (4\ 5\ 2Ë\9b\10Pi\ 2\18S!ªåÆ0\95F\ 4\8c4\82[^\90_ P\v\10`\0.§G±\rendstream\rendobj\r15 0 obj\r<</Subtype/NChannel/Process 16 0 R>>\rendobj\r16 0 obj\r<</Components[/Cyan/Magenta/Yellow/Black]/ColorSpace/DeviceCMYK>>\rendobj\r32 0 obj\r<</ColorSpace 13 0 R/AntiAlias false/Coords[0.0 0.0 1.0 0.0]/Function 33 0 R/Extend[true true]/Domain[0.0 1.0]/ShadingType 2>>\rendobj\r33 0 obj\r<</FunctionType 3/Encode[1.0 0.0 0.0 1.0]/Domain[0.0 1.0]/Functions[34 0 R 35 0 R]/Bounds[0.967026]>>\rendobj\r34 0 obj\r<</C0[0.735]/C1[0.0]/FunctionType 2/N 1.01602/Domain[0.0 1.0]>>\rendobj\r35 0 obj\r<</C0[0.735]/C1[0.735]/FunctionType 2/N 1.0/Domain[0.0 1.0]>>\rendobj\r29 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r23 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r17 0 obj\r<</ColorSpace 13 0 R/AntiAlias false/Coords[0.0 0.0 1.0 0.0]/Function 18 0 R/Extend[true true]/Domain[0.0 1.0]/ShadingType 2>>\rendobj\r18 0 obj\r<</FunctionType 3/Encode[1.0 0.0]/Domain[0.0 1.0]/Functions[19 0 R]/Bounds[]>>\rendobj\r19 0 obj\r<</C0[1.0]/C1[0.0]/FunctionType 2/N 1.01602/Domain[0.0 1.0]>>\rendobj\r9 0 obj\r<</I false/K false/S/Transparency/Type/Group>>\rendobj\r49 0 obj\r<</CreationDate(D:20090604105016-07'00')/Creator(Adobe Illustrator CS3)/Producer(Adobe PDF library 8.00)/ModDate(D:20090604105016-07'00')/Title(Netatalk_Logo)>>\rendobj\rxref\r0 51\r0000000003 65535 f\r
+0000000016 00000 n\r
+0000026186 00000 n\r
+0000000004 00001 f\r
+0000000006 00000 f\r
+0000026237 00000 n\r
+0000000007 00001 f\r
+0000000008 00001 f\r
+0000000010 00001 f\r
+0000031007 00000 n\r
+0000000012 00001 f\r
+0000027992 00000 n\r
+0000000021 00001 f\r
+0000029722 00000 n\r
+0000029782 00000 n\r
+0000030011 00000 n\r
+0000030064 00000 n\r
+0000030691 00000 n\r
+0000030834 00000 n\r
+0000030929 00000 n\r
+0000028218 00000 n\r
+0000000022 00001 f\r
+0000000024 00001 f\r
+0000030628 00000 n\r
+0000000025 00001 f\r
+0000000027 00001 f\r
+0000028579 00000 n\r
+0000000028 00001 f\r
+0000000030 00001 f\r
+0000030565 00000 n\r
+0000000031 00001 f\r
+0000000037 00001 f\r
+0000030146 00000 n\r
+0000030289 00000 n\r
+0000030407 00000 n\r
+0000030487 00000 n\r
+0000028941 00000 n\r
+0000000038 00001 f\r
+0000000040 00001 f\r
+0000029659 00000 n\r
+0000000041 00001 f\r
+0000000044 00001 f\r
+0000029300 00000 n\r
+0000028105 00000 n\r
+0000000045 00001 f\r
+0000000046 00001 f\r
+0000000000 00001 f\r
+0000026665 00000 n\r
+0000027926 00000 n\r
+0000031069 00000 n\r
+0000000077 00000 n\r
+trailer\r<</Size 51/Root 1 0 R/Info 49 0 R/ID[<8382E707CCB44A8FBBDD373DCFC0BC17><2861F2D7C5014E0FA17536D73E45D784>]>>\rstartxref\r31246\r%%EOF\r
\ No newline at end of file
diff --git a/doc/gfx_and_css/logo.png b/doc/gfx_and_css/logo.png
new file mode 100644 (file)
index 0000000..8138256
Binary files /dev/null and b/doc/gfx_and_css/logo.png differ
diff --git a/doc/gfx_and_css/netatalk.css b/doc/gfx_and_css/netatalk.css
new file mode 100644 (file)
index 0000000..8096a61
--- /dev/null
@@ -0,0 +1,251 @@
+BODY {
+       /* font-family: helvetica, arial, "lucida sans", sans-serif; */
+       font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;;
+       background-color: white;
+       font-size: 1em;
+       margin-left: 15px;
+       margin-right: 15px;
+}
+
+.pdparam{
+       /* font-family: helvetica, arial, "lucida sans", sans-serif; */
+       font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;;
+       font-size: 12px;
+}
+
+TD {
+       /* font-family: helvetica, arial, "lucida sans", sans-serif; */
+       font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;;
+       font-size: 12px;
+}
+
+H1, H2, H3 {
+       font-size: 130%;
+       padding: 2px;
+       margin-top: 0px;
+}
+
+H1 {
+       background-color: #424242;
+       color: #FFFFFF;
+}
+
+H2 {
+       background-color: #424242;
+       color: #FFFFFF;
+       text-decoration: none;
+}
+
+H3 {
+       background-color: #330000;
+       color: #FFFFFF;
+}
+
+H4 {
+       color: #330000;
+       font-size: 120%;
+}
+
+H5 {
+       font-size: 100%;
+       color: #330000;
+}
+
+.term {
+       color: black;
+}
+
+TR.qandadiv TD {
+       padding-top: 1em;
+}
+
+DIV.navheader {
+       font-size: 80%;
+       margin-top: 15px;
+}
+
+div.titlepage {
+       margin-top: 15px;
+}
+
+DIV.navheader th{
+       font-size: 100%;
+}
+
+DIV.navfooter {
+       font-size: 80%;
+}
+
+A:link {
+       color: #660000;
+}
+
+A:visited {
+       color: #CC0000;
+}
+
+A:active {
+       color: #FF0033;
+}
+
+TR.question {
+       color: #33C;
+       font-weight: bold;
+}
+
+TR.question TD {
+       padding-top: 1em;
+}
+
+DIV.variablelist {
+       padding-left: 2em;
+       color: #33C;
+}
+
+P {
+       color: black;
+}
+
+DIV.caution, DIV.tip, DIV.important {
+       border: dashed 1px;
+       background-color: #EEEEFF;
+       width: 60em;
+       padding: 5px;
+}
+
+PRE.programlisting, PRE.screen {
+       border: #630 1px dashed;
+       color: #993300;
+       padding: 2px;
+       font-size: 120%;
+}
+DIV.warning { 
+       border: dashed 1px;
+       background-color: #BFBFBF;
+       width: 60em;
+       padding: 5px;
+} 
+
+DIV.note { 
+       border: dashed 1px;
+       background-color: #f2f2f2;
+       width: 60em;
+       padding: 5px;
+} 
+
+DIV.author {
+       padding-top: 1em;
+}
+
+DIV.revhistory table{
+       font-size: 12px;
+       border-collapse: collapse;
+       border-spacing: 0;
+       border: 0px;
+}
+
+DIV.revhistory tr {
+       border: 0px;
+}
+
+DIV.revhistory td {
+       border: 0px;
+}
+
+DIV.revhistory th {
+       border: 0px;
+}
+
+div.book, div.chapter, div.refentry {
+       font-size: 12px;
+}
+
+div.indexdiv {
+       font-size: 12px;
+}
+
+tt {
+       font-size: 12px;
+}
+
+/**
+ * netatalk
+ */
+/* definitions for the header */
+div#header {
+    margin-top: 15px;
+    margin-left: -15px;
+    margin-right: -15px;
+    height: 109px;
+    white-space: nowrap;
+    background-color: #424242;
+    background-image: url(/gfx/bg.gif);
+    background-repeat: no-repeat;
+    background-position: 380px 0px;
+}
+
+div#logo {
+       position: absolute;
+       margin-top: 0px;
+       margin-left: 25px;
+       width: 225px;
+       height: 109px;
+       padding: 0px;
+       background-image: url(/gfx/netatalklogo.gif);
+       background-repeat: no-repeat;
+}
+
+#logo img {
+    border: 0px;
+}
+
+div#menlinks {
+       position: absolute;
+       left: 272px;
+       top: 102px;
+       font-family: Geneva, Arial, Helvetica, sans-serif;
+       font-size: 12px;
+       font-weight: normal;
+       color: #FFFFFF;
+       text-decoration: none;
+       white-space: nowrap;
+
+}
+
+div#menlinks a, div#menlinks a:visited {
+    color: #FFFFFF;
+    margin-right: 15px;
+    text-decoration: none;
+}
+
+#menlinks img {
+   border: 0px;
+}
+
+.italic {
+        font-family: Geneva, Arial, Helvetica, sans-serif;
+        font-size: 11px;
+        font-style: italic;
+        font-weight: normal;
+        color: #000000;
+        text-decoration: none;
+}
+
+a, a:visited {
+  text-decoration: none;
+  color: #660000;
+}
+
+/* definitions for the footer */
+div.footer {
+       margin-left: 210px;
+       margin-top: 22px;
+       font-size: 75%;
+       width: 145px;
+       text-align: left;
+       white-space: nowrap;
+}
+
+.footer img {
+   padding-right: 5px;
+}
diff --git a/doc/html.xsl.in b/doc/html.xsl.in
new file mode 100644 (file)
index 0000000..b2fbfd3
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0'?> 
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
+       <xsl:import href="@DOCBOOK_ROOT@/xhtml/chunk.xsl"/> 
+       <xsl:param name="use.id.as.filename" select="'1'"/>
+       <xsl:param name="chunk.section.depth" select="0"></xsl:param>
+       <xsl:param name="chunk.separate.lots" select="1"></xsl:param>
+       <xsl:param name="html.stylesheet" select="'http://netatalk.sourceforge.net/css/netatalk.css'"/>
+
+       <xsl:template name="user.header.navigation">
+               <xsl:variable name="codefile" select="document('netatalk.html',/)"/>
+               <xsl:copy-of select="$codefile/*/node()"/>
+       </xsl:template>
+</xsl:stylesheet>
diff --git a/doc/man.xsl.in b/doc/man.xsl.in
new file mode 100644 (file)
index 0000000..fca9fec
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version='1.0'?> 
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
+<xsl:import href="@DOCBOOK_ROOT@/manpages/docbook.xsl"/> 
+
+<!-- * Collect date from <refmiscinfo class="date"> -->
+<xsl:param name="refentry.date.profile.enabled">1</xsl:param>
+<xsl:param name="refentry.date.profile">
+  (//refmiscinfo[@class='date'])[last()]
+</xsl:param>
+
+<!-- * Suppress extra :VERSION: -->
+<xsl:param name="refentry.version.suppress">1</xsl:param>
+
+<!-- * Example without numbering -->
+<xsl:param name="local.l10n.xml" select="document('')"/>
+<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
+<l:l10n language="en">
+ <l:context name="title">
+    <l:template name="example" text="Example.&#160;%t"/>
+ </l:context>
+ <l:context name="title-numbered">
+    <l:template name="example" text="Example.&#160;%t"/>
+ </l:context>
+</l:l10n>
+</l:i18n>
+</xsl:stylesheet>
diff --git a/doc/manpages/man1/ad.1.xml b/doc/manpages/man1/ad.1.xml
new file mode 100644 (file)
index 0000000..3163d06
--- /dev/null
@@ -0,0 +1,402 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="ad.1">
+  <refmeta>
+    <refentrytitle>ad</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">02 Sep 2011</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>ad</refname>
+
+    <refpurpose>Netatalk compatible UNIX file utility suite.</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>ad</command>
+
+      <arg choice="req">ls | cp | mv | rm</arg>
+
+      <arg>...</arg>
+    </cmdsynopsis>
+
+    <cmdsynopsis>
+      <command>ad</command>
+
+      <arg choice="req">-v | --version</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><command>ad</command> is a UNIX file utility suite with Netatalk
+    compatibility. AppleDouble<indexterm>
+        <primary>AppleDouble</primary>
+      </indexterm> files in <filename>.AppleDouble</filename> directories and
+    the CNID databases are updated as appropriate.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Available Commands</title>
+
+    <cmdsynopsis>
+      <command>ad ls</command>
+
+      <arg>-dRl<arg>u</arg></arg>
+
+      <arg choice="req">file|dir <arg>...</arg></arg>
+    </cmdsynopsis>
+
+    <para>List files and directories.</para>
+
+    <cmdsynopsis>
+      <command>ad cp</command>
+
+      <arg choice="opt">-aipvf</arg>
+
+      <arg choice="req">src_file</arg>
+
+      <arg choice="req">dst_file</arg>
+    </cmdsynopsis>
+
+    <cmdsynopsis>
+      <command>ad cp -R</command>
+
+      <arg choice="opt">-aipvf</arg>
+
+      <arg choice="req">src_file|src_directory ...</arg>
+
+      <arg choice="req">dst_directory</arg>
+    </cmdsynopsis>
+
+    <para>Copy files and directories.</para>
+
+    <cmdsynopsis>
+      <command>ad mv</command>
+
+      <arg choice="opt">-finv</arg>
+
+      <arg choice="req">src_file</arg>
+
+      <arg choice="req">dst_file</arg>
+    </cmdsynopsis>
+
+    <cmdsynopsis>
+      <command>ad mv</command>
+
+      <arg choice="opt">-finv</arg>
+
+      <arg choice="req">src_file|src_directory ...</arg>
+
+      <arg choice="req">dst_directory</arg>
+    </cmdsynopsis>
+
+    <para>Move files and directories.</para>
+
+    <cmdsynopsis>
+      <command>ad rm</command>
+
+      <arg choice="opt">-Rv</arg>
+
+      <arg choice="req">file|directory</arg>
+    </cmdsynopsis>
+
+    <cmdsynopsis>
+      <command>ad -v|--version</command>
+    </cmdsynopsis>
+
+    <para>Show version.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>ad ls</title>
+
+    <para>List files and directories. Options:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term>-d</term>
+
+        <listitem>
+          <para>Directories are listed as plain files</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-R</term>
+
+        <listitem>
+          <para>list subdirectories recursively</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-l</term>
+
+        <listitem>
+          <para>Long output, list AFP info</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-u</term>
+
+        <listitem>
+          <para>List UNIX info</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+
+    <para><emphasis>Long output description</emphasis></para>
+
+    <programlisting>&lt;unixinfo&gt; &lt;FinderFlags&gt; &lt;AFP Attributes&gt; &lt;Color&gt; &lt;Type&gt; &lt;Creator&gt; &lt;CNID from AppleDouble&gt; &lt;name&gt;
+
+FinderFlags (valid for (f)iles and/or (d)irectories):
+
+  d = On Desktop                      (f/d)
+  e = Hidden extension                (f/d)
+  m = Shared (can run multiple times) (f)
+  n = No INIT resources               (f)
+  i = Inited                          (f/d)
+  c = Custom icon                     (f/d)
+  t = Stationery                      (f)
+  s = Name locked                     (f/d)
+  b = Bundle                          (f/d)
+  v = Invisible                       (f/d)
+  a = Alias file                      (f/d)
+
+AFP Attributes:
+
+  y = System                          (f/d)
+  w = No write                        (f)
+  p = Needs backup                    (f/d)
+  r = No rename                       (f/d)
+  l = No delete                       (f/d)
+  o = No copy                         (f)
+
+Note: any letter appearing in uppercase means the flag is set but it's a directory for which the flag is not allowed.</programlisting>
+  </refsect1>
+
+  <refsect1>
+    <title>ad cp</title>
+
+    <para>Copy files and directories.</para>
+
+    <para>In the first synopsis form, the cp utility copies the contents of
+    the source_file to the target_file. In the second synopsis form, the
+    contents of each named source_file is copied to the destination
+    target_directory. The names of the files themselves are not changed. If cp
+    detects an attempt to copy a file to itself, the copy will fail.</para>
+
+    <para>Netatalk AFP volumes are detected by means of their ".AppleDesktop"
+    directory which is located in their volume root. When a copy targeting an
+    AFP volume is detected, its CNID database daemon is connected and all
+    copies will also go through the CNID database. AppleDouble files are also
+    copied and created as needed when the target is an AFP volume.</para>
+
+    <para>Options:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term>-a</term>
+
+        <listitem>
+          <para>Archive mode. Same as -Rp.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-f</term>
+
+        <listitem>
+          <para>For each existing destination pathname, remove it and create a
+          new file, without prompting for confirmation regardless of its
+          permis- sions. (The -f option overrides any previous -i or -n
+          options.)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-i</term>
+
+        <listitem>
+          <para>Cause cp to write a prompt to the standard error output before
+          copying a file that would overwrite an existing file. If the
+          response from the standard input begins with the character 'y' or
+          'Y', the file copy is attempted. (The -i option overrides any pre-
+          vious -f or -n options.)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-n</term>
+
+        <listitem>
+          <para>Do not overwrite an existing file. (The -n option overrides
+          any previous -f or -i options.)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-p</term>
+
+        <listitem>
+          <para>Cause cp to preserve the following attributes of each source
+          file in the copy: modification time, access time, file flags, file
+          mode, user ID, and group ID, as allowed by permissions. If the user
+          ID and group ID cannot be preserved, no error message is displayed
+          and the exit value is not altered.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-R</term>
+
+        <listitem>
+          <para>If source_file designates a directory, cp copies the directory
+          and the entire subtree connected at that point.If the source_file
+          ends in a /, the contents of the directory are copied rather than
+          the directory itself.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-v</term>
+
+        <listitem>
+          <para>Cause cp to be verbose, showing files as they are
+          copied.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-x</term>
+
+        <listitem>
+          <para>File system mount points are not traversed.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>ad mv</title>
+
+    <para>Move files and directories.</para>
+
+    <para>Move files around within an AFP volume, updating the CNID database
+    as needed. If either:<itemizedlist>
+        <listitem>
+          <para>source or destination is not an AFP volume</para>
+        </listitem>
+
+        <listitem>
+          <para>source AFP volume != destination AFP volume</para>
+        </listitem>
+      </itemizedlist>the files are copied and removed from the source.</para>
+
+    <para>Options:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term>-f</term>
+
+        <listitem>
+          <para>Do not prompt for confirmation before overwriting the
+          destination path. (The -f option overrides any previous -i or -n
+          options.)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-i</term>
+
+        <listitem>
+          <para>Cause mv to write a prompt to standard error before moving a
+          file that would overwrite an existing file. If the response from the
+          standard input begins with the character `y' or `Y', the move is
+          attempted. (The -i option overrides any previous -f or -n
+          options.)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-n</term>
+
+        <listitem>
+          <para>Do not overwrite an existing file. (The -n option overrides
+          any previous -f or -i options.)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-v</term>
+
+        <listitem>
+          <para>Cause mv to be verbose, showing files after they are
+          moved.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>ad rm</title>
+
+    <para>Remove files and directories.</para>
+
+    <para>The rm utility attempts to remove the non-directory type files
+    specified on the command line. If the files and directories reside on an
+    AFP volume, the corresponding CNIDs are deleted from the volumes
+    database.</para>
+
+    <para>The options are as follows:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term>-R</term>
+
+        <listitem>
+          <para>Attempt to remove the file hierarchy rooted in each file
+          argument.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-v</term>
+
+        <listitem>
+          <para>Be verbose when deleting files, showing them as they are
+          removed.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Reporting Bugs</title>
+
+    <para>Report bugs to the Netatalk-devel list
+    &lt;netatalk-devel@lists.sourceforge.net&gt;.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See also</title>
+
+    <para><citerefentry>
+        <refentrytitle>dbd</refentrytitle>
+
+        <manvolnum>1</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>apple_dump</refentrytitle>
+
+        <manvolnum>1</manvolnum>
+      </citerefentry>.</para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/afpldaptest.1.xml b/doc/manpages/man1/afpldaptest.1.xml
new file mode 100644 (file)
index 0000000..52ec6d3
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="afpldaptest.1">
+  <refmeta>
+    <refentrytitle>afpldaptest</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">22 Mar 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv id="name">
+    <refname>afpldaptest</refname>
+
+    <refpurpose>Syntactically check ldap parameters in afp.conf</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv id="synopsis">
+    <cmdsynopsis>
+      <command>afpldaptest<indexterm><primary>afpldaptest</primary></indexterm></command>
+
+      <group choice="req">
+        <arg choice="plain">-u <replaceable>USER</replaceable></arg>
+        <arg choice="plain">-g <replaceable>GROUP</replaceable></arg>
+        <arg choice="plain">-i <replaceable>UUID</replaceable></arg>
+      </group>
+
+      <sbr />
+
+      <command>afpldaptest<indexterm><primary>afpldaptest</primary></indexterm></command>
+
+      <group choice="req">
+        <arg choice="plain">-h</arg>
+        <arg choice="plain">-?</arg>
+        <arg choice="plain">-:</arg>
+      </group>
+
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1 id="description">
+    <title>DESCRIPTION</title>
+
+    <para><command>afpldaptest</command> is a simple command to syntactically
+    check ldap parameters in :ETCDIR:/afp.conf.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>-u</option> <replaceable>USER</replaceable></term>
+
+        <listitem>
+          <para>Show uuid for <replaceable>USER</replaceable>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-g</option> <replaceable>GROUP</replaceable></term>
+
+        <listitem>
+          <para>Show uuid for <replaceable>GROUP</replaceable>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-i</option> <replaceable>UUID</replaceable></term>
+
+        <listitem>
+          <para>Show user, group or local-uuid for
+         <replaceable>UUID</replaceable>.</para>
+        </listitem>
+
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-h, -?, -:</option></term>
+
+        <listitem>
+          <para>Show the help and exit.</para>
+        </listitem>
+
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1 id="see_also">
+    <title>SEE ALSO</title>
+
+    <para><citerefentry><refentrytitle>afp.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/afppasswd.1.xml b/doc/manpages/man1/afppasswd.1.xml
new file mode 100644 (file)
index 0000000..ccd5ee6
--- /dev/null
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="afppasswd.1">
+  <refmeta>
+    <refentrytitle>afppasswd</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">22 Mar 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>afppasswd</refname>
+
+    <refpurpose>netatalk password maintenance utility</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>afppasswd<indexterm>
+          <primary>afppasswd</primary>
+        </indexterm><indexterm>
+          <primary>UAM</primary>
+
+          <secondary>User Authentication Module</secondary>
+        </indexterm></command>
+
+      <arg choice="opt">-acfn</arg>
+
+      <arg choice="opt"><arg choice="plain">-p
+      <replaceable>passwd</replaceable></arg><arg
+      choice="plain"><replaceable>file</replaceable></arg></arg>
+
+      <arg choice="opt"><arg choice="plain">-u
+      <replaceable>minimum</replaceable></arg><arg
+      choice="plain"><replaceable>uid</replaceable></arg></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para><command>afppasswd</command> allows the maintenance of afppasswd
+    files created by netatalk for use by the uams_randnum.so UAM (providing
+    the "Randnum exchange" and "2-Way Randnum exchange" User Authentication
+    Modules).</para>
+
+    <para><command>afppasswd</command> can either be called by root with
+    parameters, or can be called by local system users with no parameters to
+    change their AFP passwords.</para>
+
+    <note>
+      <para>With this utility you can only change the passwords used by two
+      specific UAMs. As they provide only weak password encryption, the use of
+      the "Randnum exchange" and "2-Way Randnum exchange" UAMs is deprecated
+      unless one has to support very old AFP clients, that can not deal with
+      the more secure "DHCAST128" and "DHX2" UAM instead. Please compare with
+      the <link linkend="authentication">Authentication chapter</link> inside
+      Netatalk's documentation.</para>
+    </note>
+  </refsect1>
+
+  <refsect1>
+    <title>EXAMPLE</title>
+
+    <para>Local user changing their own password:</para>
+
+    <screen><prompt>example%</prompt> <userinput>afppasswd</userinput>
+<computeroutput>Enter NEW AFP password:</computeroutput> <userinput>(hidden)</userinput>
+<computeroutput>Enter NEW AFP password again:</computeroutput> <userinput>(hidden)</userinput>
+<computeroutput>afppasswd: updated password.</computeroutput>
+</screen>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>-a</option></term>
+
+        <listitem>
+          <para>Add a new user to the <command>afppasswd</command>
+          file.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-c</option></term>
+
+        <listitem>
+          <para>Create and/or initialize <command>afppasswd</command> file or
+          specific user.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-f</option></term>
+
+        <listitem>
+          <para>Force the current action.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-p</option><replaceable> path</replaceable></term>
+
+        <listitem>
+          <para>Path to <command>afppasswd</command> file.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-n</option></term>
+
+        <listitem>
+          <para>If cracklib support is built into <emphasis
+          remap="B">netatalk</emphasis> this option will cause cracklib
+          checking to be disabled, if the superuser does not want to have the
+          password run against the cracklib dictionary.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-u</option><replaceable> minimum
+        uid</replaceable></term>
+
+        <listitem>
+          <para>This is the minimum <emphasis remap="I">user id</emphasis>
+          (uid) that <command>afppasswd</command> will use when creating
+          users.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para><citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>.</para>
+  </refsect1>
+</refentry>
\ No newline at end of file
diff --git a/doc/manpages/man1/afpstats.1.xml b/doc/manpages/man1/afpstats.1.xml
new file mode 100644 (file)
index 0000000..b1ab94f
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="afpstats.1">
+  <refmeta>
+    <refentrytitle>afpstats</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">24 Mar 2013</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv id="name">
+    <refname>afpstats</refname>
+
+    <refpurpose>List AFP statistics</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv id="synopsis">
+    <cmdsynopsis>
+      <command>afpstats<indexterm><primary>afpstats</primary></indexterm></command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1 id="description">
+    <title>DESCRIPTION</title>
+
+    <para><command>afpstats</command> list AFP statistics via D-Bus IPC.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>NOTE</title>
+
+    <para><command>afpd</command> must support D-Bus. Check it by
+    "<command>afpd -V</command>".</para>
+
+    <para>"<option>afpstats = yes</option>" must be set in
+    <filename>:ETCDIR:/afp.conf</filename>.</para>
+
+  </refsect1>
+
+  <refsect1 id="see_also">
+    <title>SEE ALSO</title>
+
+    <para><citerefentry><refentrytitle>afpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>afp.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/apple_dump.1.xml b/doc/manpages/man1/apple_dump.1.xml
new file mode 100644 (file)
index 0000000..1723a30
--- /dev/null
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="apple_dump.1">
+  <refmeta>
+    <refentrytitle>apple_dump</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">16 Jul 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv id="name">
+    <refname>apple_dump</refname>
+
+    <refpurpose>Dump AppleSingle/AppleDouble format data</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv id="synopsis">
+    <cmdsynopsis>
+      <command>apple_dump<indexterm><primary>apple_dump</primary></indexterm></command>
+
+      <arg choice="opt"><arg choice="plain">-a</arg></arg>
+
+      <group choice="opt">
+        <arg choice="plain"><replaceable>FILE</replaceable></arg>
+        <arg choice="plain"><replaceable>DIR</replaceable></arg>
+      </group>
+
+      <sbr />
+
+      <command>apple_dump<indexterm><primary>apple_dump</primary></indexterm></command>
+
+      <arg choice="plain">-e</arg>
+
+      <group choice="plain">
+        <arg choice="plain"><replaceable>FILE</replaceable></arg>
+        <arg choice="plain"><replaceable>DIR</replaceable></arg>
+      </group>
+
+      <sbr />
+
+      <command>apple_dump<indexterm><primary>apple_dump</primary></indexterm></command>
+
+      <arg choice="plain">-f</arg>
+
+      <arg choice="opt"><replaceable>FILE</replaceable></arg>
+
+      <sbr />
+
+      <command>apple_dump<indexterm><primary>apple_dump</primary></indexterm></command>
+
+      <arg choice="plain">-d</arg>
+
+      <arg choice="opt"><replaceable>FILE</replaceable></arg>
+
+      <sbr />
+
+      <command>apple_dump<indexterm><primary>apple_dump</primary></indexterm></command>
+
+      <group choice="plain">
+        <arg choice="plain">-h</arg>
+        <arg choice="plain">-help</arg>
+        <arg choice="plain">--help</arg>
+      </group>
+
+      <sbr />
+
+      <command>apple_dump<indexterm><primary>apple_dump</primary></indexterm></command>
+
+      <group choice="plain">
+        <arg choice="plain">-v</arg>
+        <arg choice="plain">-version</arg>
+        <arg choice="plain">--version</arg>
+      </group>
+
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1 id="description">
+    <title>DESCRIPTION</title>
+
+    <para><command>apple_dump</command> is a perl script to dump
+    AppleSingle/AppleDouble format data. </para>
+    <para>This script can dump various AppleSingle/AppleDouble data created
+    by mailer, archiver, Mac OS X, Netatalk and so on.</para>
+    <para>With no <replaceable>FILE</replaceable>|<replaceable>DIR</replaceable>, or when <replaceable>FILE</replaceable>|<replaceable>DIR</replaceable> is -, read standard input.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>-a</option> [<replaceable>FILE</replaceable>|<replaceable>DIR</replaceable>]</term>
+
+        <listitem>
+          <para>This is default.
+          Dump a AppleSingle/AppleDouble file for
+          <replaceable>FILE</replaceable> or <replaceable>DIR</replaceable>
+          automatically.
+          If FILE is not AppleSingle/AppleDouble format,
+          look for extended attribute, 
+          <replaceable>.AppleDouble/FILE</replaceable> and
+          <replaceable>._FILE</replaceable>.
+          If <replaceable>DIR</replaceable>, look for
+          extended attribute, 
+          <replaceable>DIR/.AppleDouble/.Parent</replaceable> and
+          <replaceable>._DIR</replaceable>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-e</option> <replaceable>FILE</replaceable>|<replaceable>DIR</replaceable></term>
+
+        <listitem>
+          <para>Dump extended attribute of<replaceable>FILE</replaceable> or <replaceable>DIR</replaceable>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-f</option> [<replaceable>FILE</replaceable>]</term>
+
+        <listitem>
+          <para>Dump <replaceable>FILE</replaceable>. Assume FinderInfo to be FileInfo.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-d</option> [<replaceable>FILE</replaceable>]</term>
+
+        <listitem>
+          <para>Dump <replaceable>FILE</replaceable>. Assume FinderInfo to be DirInfo.</para>
+        </listitem>
+
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-h, -help, --help</option></term>
+
+        <listitem>
+          <para>Display the help and exit</para>
+        </listitem>
+
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-v, -version, --version</option></term>
+
+        <listitem>
+          <para>Show version and exit</para>
+        </listitem>
+
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>NOTE</title>
+
+    <para>There is no way to detect whether FinderInfo is FileInfo or DirInfo.
+    By default, apple_dump examines whether file or directory, a parent directory
+    is .AppleDouble, filename is ._*, filename is .Parent, and so on.</para>
+
+    <para>If setting option -e, -f or -d,  assume FinderInfo and doesn't look
+    for another file.</para>
+
+  </refsect1>
+
+  <refsect1 id="see_also">
+    <title>SEE ALSO</title>
+
+    <para><citerefentry><refentrytitle>ad</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>getfattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>attr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>runat</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>getextattr</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>lsextattr</refentrytitle><manvolnum>8</manvolnum></citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/asip-status.pl.1.xml b/doc/manpages/man1/asip-status.pl.1.xml
new file mode 100644 (file)
index 0000000..d8d5b8d
--- /dev/null
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="asip-status.pl.1">
+  <refmeta>
+    <refentrytitle>asip-status.pl</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">24 Jul 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>asip-status.pl</refname>
+
+    <refpurpose>Queries AFP servers for their capabilities</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>asip-status.pl<indexterm>
+          <primary>asip-status.pl</primary>
+        </indexterm></command>
+
+      <arg choice="opt">-d</arg>
+      <arg choice="opt">-i</arg>
+      <arg choice="opt">-x</arg>
+
+      <arg choice="plain">HOSTNAME[:PORT]</arg>
+    </cmdsynopsis>
+
+    <sbr />
+
+    <cmdsynopsis>
+      <command>asip-status.pl<indexterm>
+          <primary>asip-status.pl</primary>
+        </indexterm></command>
+
+      <group choice="plain">
+        <arg choice="plain">-v</arg>
+        <arg choice="plain">-version</arg>
+        <arg choice="plain">--version</arg>
+      </group>
+    </cmdsynopsis>
+
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para><emphasis remap="B">asip-status.pl</emphasis> is a perl script that
+    sends a FPGetSrvrInfo request to an AFP server at HOSTNAME:PORT and
+    displays the results, namely "Machine type", the server's name, supported
+    AFP versions, UAMs and AFP flags, the "server signature" and the network
+    addresses, the server provides AFP services on.</para>
+
+    <para>When you don't supply :PORT, then the default AFP port, 548, will be
+    used.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>-d</option></term>
+
+        <listitem>
+          <para>Enable debug output.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-i</option></term>
+
+        <listitem>
+          <para>Show icon if it exists.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-x</option></term>
+
+        <listitem>
+          <para>Enable hex dump output.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-v, -version, --version</option></term>
+
+        <listitem>
+          <para>Show version.</para>
+        </listitem>
+
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>EXAMPLES</title>
+
+    <para><programlisting><emphasis remap="B">asip-status.pl</emphasis> 192.168.1.15
+AFP reply from 192.168.1.15:548
+Flags: 1  Cmd: 3  ID: 57005
+Reply: DSIGetStatus
+Request ID: 57005
+Machine type: Macintosh
+AFP versions: AFPVersion 1.1,AFPVersion 2.0,AFPVersion 2.1,AFP2.2
+UAMs: Cleartxt passwrd,Randnum exchange,2-Way Randnum exchange
+Volume Icon &amp; Mask: Yes
+Flags: 
+    SupportsCopyFile
+    SupportsChgPwd
+    SupportsServerMessages
+    SupportsServerSignature
+    SupportsTCP/IP
+    SupportsSuperClient
+Server name: bookchan
+Signature:
+04 1d 65 23 04 1d 65 23 04 1d 65 23 04 1d 65 23  ..e#..e#..e#..e#
+                                                  
+Network address: 192.168.1.15:548 (TCP/IP address and port)
+Network address: 65280.128 (ddp address)
+</programlisting></para>
+
+    <para><programlisting><emphasis remap="B">asip-status.pl</emphasis> myserver:10548
+AFP reply from myserver:10548
+Flags: 1  Cmd: 3  ID: 57005
+Reply: DSIGetStatus
+Request ID: 57005
+Machine type: Netatalk3.0
+AFP versions: AFP2.2,AFPX03,AFP3.1,AFP3.2,AFP3.3
+UAMs: DHX2,DHCAST128
+Volume Icon &amp; Mask: Yes
+Flags: 
+    SupportsCopyFile
+    SupportsServerMessages
+    SupportsServerSignature
+    SupportsTCP/IP
+    SupportsSrvrNotifications
+    SupportsOpenDirectory
+    SupportsUTF8Servername
+    SupportsUUIDs
+    SupportsExtSleep
+    SupportsSuperClient
+Server name: myserver
+Signature:
+8a c6 12 3a 0e d9 95 3e 6f 31 e3 a9 17 f5 70 f6  ...:...>o1....p.
+                                                  
+Network address: 192.168.1.154:10548 (TCP/IP address and port)
+UTF8 Servername: myserver
+</programlisting></para>
+  </refsect1>
+
+  <refsect1>
+    <title>REPORTING BUGS</title>
+
+    <para>Report bugs to the Netatalk-devel list
+    &lt;netatalk-devel@lists.sourceforge.net&gt;.</para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/dbd.1.xml b/doc/manpages/man1/dbd.1.xml
new file mode 100644 (file)
index 0000000..b3043f3
--- /dev/null
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="dbd.1">
+  <refmeta>
+    <refentrytitle>dbd</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">28 Dec 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>dbd</refname>
+
+    <refpurpose>CNID database maintenance</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>dbd<indexterm>
+          <primary>dbd</primary>
+        </indexterm></command>
+
+      <arg choice="opt">-fsv</arg>
+
+      <arg choice="plain"><replaceable>volumepath</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><command>dbd</command> scans all file and directories of AFP
+    volumes, updating the CNID database of the volume. It must be run with
+    appropriate permissions i.e. as root..</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+
+    <variablelist>
+      <varlistentry>
+        <term>-c</term>
+
+        <listitem>
+          <para>convert from adouble:v2 to adouble:ea</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-f</term>
+
+        <listitem>
+          <para>delete and recreate CNID database</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-F</term>
+
+        <listitem>
+          <para>location of the afp.conf config file</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-s</term>
+
+        <listitem>
+          <para>scan volume: treat the volume as read only and don't perform
+          any filesystem modifications</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-t</term>
+
+        <listitem>
+          <para>show statistics while running</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-v</term>
+
+        <listitem>
+          <para>verbose</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-V</term>
+
+        <listitem>
+          <para>display version info</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>CNID background</title>
+
+    <para>The CNID backends maintains name to ID mappings. If you change a
+    filename outside afpd(8) (shell, samba), the CNID database will not
+    reflect that change. Netatalk tries to recover from such inconsistencies
+    as gracefully as possible.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See also</title>
+
+    <para><citerefentry>
+        <refentrytitle>cnid_metad</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>cnid_dbd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/macusers.1.xml b/doc/manpages/man1/macusers.1.xml
new file mode 100644 (file)
index 0000000..6f0abb1
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="macusers.1">
+  <refmeta>
+    <refentrytitle>macusers</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">13 Oct 2011</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv id="name">
+    <refname>macusers</refname>
+
+    <refpurpose>List the users connecting via AFP</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv id="synopsis">
+    <cmdsynopsis>
+      <command>macusers<indexterm><primary>macusers</primary></indexterm></command>
+    </cmdsynopsis>
+
+    <cmdsynopsis>
+      <command>macusers<indexterm><primary>macusers</primary></indexterm></command>
+
+      <group choice="plain">
+        <arg choice="plain">-v</arg>
+        <arg choice="plain">-version</arg>
+        <arg choice="plain">--version</arg>
+        <arg choice="plain">-h</arg>
+        <arg choice="plain">-help</arg>
+        <arg choice="plain">--help</arg>
+      </group>
+
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1 id="description">
+    <title>DESCRIPTION</title>
+
+    <para><command>macusers</command> list the users connecting via AFP.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>-v, -version, --version</option></term>
+
+        <listitem>
+          <para>Show version and exit</para>
+        </listitem>
+
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-h, -help, --help</option></term>
+
+        <listitem>
+          <para>Display the help and exit</para>
+        </listitem>
+
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1 id="see_also">
+    <title>SEE ALSO</title>
+
+    <para><citerefentry><refentrytitle>afpd</refentrytitle><manvolnum>8</manvolnum></citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/megatron.1.xml b/doc/manpages/man1/megatron.1.xml
new file mode 100644 (file)
index 0000000..34c3d0c
--- /dev/null
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="megatron.1">
+  <refmeta>
+    <refentrytitle>megatron</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">02 Sep 2011</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv id="name">
+    <refname>megatron</refname>
+
+    <refname>unhex</refname>
+
+    <refname>unbin</refname>
+
+    <refname>unsingle</refname>
+
+    <refname>hqx2bin</refname>
+
+    <refname>single2bin</refname>
+
+    <refname>macbinary</refname>
+
+    <refpurpose>Macintosh file format transformer</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv id="synopsis">
+    <cmdsynopsis>
+      <command>megatron<indexterm><primary>megatron</primary></indexterm></command>
+
+      <arg choice="opt" rep="repeat"><replaceable>sourcefile</replaceable></arg>
+
+      <sbr />
+
+      <command>unbin<indexterm><primary>unbin</primary></indexterm></command>
+
+      <arg choice="opt" rep="repeat"><replaceable>sourcefile</replaceable></arg>
+
+      <sbr />
+
+      <command>unhex<indexterm><primary>unhex</primary></indexterm></command>
+
+      <arg choice="opt" rep="repeat"><replaceable>sourcefile</replaceable></arg>
+
+      <sbr />
+
+      <command>unsingle<indexterm><primary>unsingle</primary></indexterm></command>
+
+      <arg choice="opt" rep="repeat"><replaceable>sourcefile</replaceable></arg>
+
+      <sbr />
+
+      <command>hqx2bin<indexterm><primary>hqx2bin</primary></indexterm></command>
+
+      <arg choice="opt" rep="repeat"><replaceable>sourcefile</replaceable></arg>
+
+      <sbr />
+
+      <command>single2bin<indexterm><primary>single2bin</primary></indexterm></command>
+
+      <arg choice="opt" rep="repeat"><replaceable>sourcefile</replaceable></arg>
+
+      <sbr />
+
+      <command>macbinary<indexterm><primary>macbinary</primary></indexterm></command>
+
+      <arg choice="opt" rep="repeat"><replaceable>sourcefile</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1 id="description">
+    <title>DESCRIPTION</title>
+
+    <para><command>megatron</command> is used to transform files from BinHex,
+    MacBinary, AppleSingle, or <emphasis remap="B" role="bold">netatalk</emphasis> style
+    AppleDouble formats into MacBinary or <emphasis remap="B">netatalk</emphasis>
+    style AppleDouble formats. The <emphasis remap="B">netatalk</emphasis>
+    style AppleDouble format is the file format used by <emphasis remap="B">afpd,</emphasis>
+    the <emphasis remap="B">netatalk</emphasis> Apple Filing Protocol
+    (AppleShare) server. BinHex, MacBinary, and AppleSingle are commonly used
+    formats for transferring Macintosh files between machines via email or
+    file transfer protocols. <command>megatron</command> uses its name to
+    determine what type of transformation is being asked of it.</para>
+
+    <para>If <command>megatron</command> is called as <command>unhex</command>
+    , <command>unbin</command> or <command>unsingle</command>, it tries to
+    convert file(s) from BinHex, MacBinary, or AppleSingle into AppleDouble
+    format. BinHex is the format most often used to send Macintosh files by
+    e-mail. Usually these files have an extension of &#34;.hqx&#34;. MacBinary
+    is the format most often used by terminal emulators &#34;on the fly&#34;
+    when transferring Macintosh files in binary mode. MacBinary files often
+    have an extension of &#34;.bin&#34;. Some Macintosh LAN-based email
+    packages use uuencoded AppleSingle format to &#34;attach&#34; or
+    &#34;enclose&#34; files in email. AppleSingle files don&#39;t have a
+    standard filename extension.</para>
+
+    <para>If <command>megatron</command> is called as <command>hqx2bin</command>,
+    <command>single2bin</command>, or <command>macbinary</command>, it will
+    try to convert the file(s) from BinHex, AppleSingle, or AppleDouble into
+    MacBinary. This last translation may be useful in moving Macintosh files
+    from your <command>afpd</command> server to some other machine when you
+    can&#39;t copy them from the server using a Macintosh for some reason.</para>
+
+    <para>If <command>megatron</command> is called with any other name, it
+    uses the default translation, namely <command>unhex</command>.</para>
+
+    <para>If no source file is given, or if <emphasis remap="I">sourcefile</emphasis>
+    is `<emphasis remap="" role="bold">-</emphasis>&#39;, and if the
+    conversion is from a BinHex or MacBinary file, <command>megatron</command>
+    will read from standard input.</para>
+
+    <para>The filename used to store any output file is the filename that is
+    encoded in the source file. MacBinary files are created with a
+    &#34;.bin&#34; extension. In the case of conflicts, the old file is
+    overwritten!</para>
+  </refsect1>
+
+  <refsect1 id="options">
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>-v, --version</option></term>
+
+        <listitem>
+          <para>Show version.</para>
+        </listitem>
+
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1 id="see_also">
+    <title>SEE ALSO</title>
+
+    <para><citerefentry><refentrytitle>afpd</refentrytitle><manvolnum>8</manvolnum></citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/netatalk-config.1.xml b/doc/manpages/man1/netatalk-config.1.xml
new file mode 100644 (file)
index 0000000..391ae5c
--- /dev/null
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="netatalkconfig.1">
+  <refmeta>
+    <refentrytitle>netatalk-config</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">09 June 2001</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+
+    <refmiscinfo class="manual">The Netatalk Project</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>netatalk-config</refname>
+
+    <refpurpose>script to get information about the installed version of
+    netatalk</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>netatalk-config<indexterm><primary>netatalk-config</primary></indexterm></command>
+
+      <arg choice="opt"><arg choice="plain">--prefix </arg><arg choice="opt"><replaceable>=DIR</replaceable></arg></arg>
+
+      <arg choice="opt"><arg choice="plain">--exec_prefix </arg><arg
+      choice="opt"><replaceable>=DIR</replaceable></arg></arg>
+
+      <arg choice="opt">--help</arg>
+
+      <arg choice="opt">--version</arg>
+
+      <arg choice="opt">--libs</arg>
+
+      <arg choice="opt">--libs-dirs</arg>
+
+      <arg choice="opt">--libs-names</arg>
+
+      <arg choice="opt">--cflags</arg>
+
+      <arg choice="opt">--macros</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para><command>netatalk-config</command> is a tool that is used to
+    determine the compiler and linker flags that should be used
+    to compile and link programs that use the <emphasis remap="I">netatalk</emphasis>
+    run-time libraries.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para><command>netatalk-config</command> accepts the following options:</para>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>--help</option></term>
+
+        <listitem>
+          <para>Print a short help for this command and exit.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--version</option></term>
+
+        <listitem>
+          <para>Print the currently installed version of <emphasis remap="I">netatalk</emphasis>
+          on the standard output.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--libs</option></term>
+
+        <listitem>
+          <para>Print the linker flags that are necessary to link against the
+          <emphasis remap="I">netatalk</emphasis> run-time libraries.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--libs-dirs</option></term>
+
+        <listitem>
+          <para>Print only the -l/-R part of --libs.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--libs-names</option></term>
+
+        <listitem>
+          <para>Print only the -l part of --libs.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--cflags</option></term>
+
+        <listitem>
+          <para>Print the compiler flags that are necessary to compile a
+          program linked against the <emphasis remap="I">netatalk</emphasis>
+          run-time libraries.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--macros</option></term>
+
+        <listitem>
+          <para>Print the <emphasis remap="I">netatalk</emphasis> m4
+          directory.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--prefix=PREFIX</option></term>
+
+        <listitem>
+          <para>If specified, use PREFIX instead of the installation prefix
+          that <emphasis remap="I">netatalk</emphasis> was built with when
+          computing the output for the --cflags and --libs options. This
+          option is also used for the exec prefix if --exec-prefix was not
+          specified. This option must be specified before any --libs or
+          --cflags options.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--exec\_prefix=PREFIX</option></term>
+
+        <listitem>
+          <para>If specified, use PREFIX instead of the installation exec
+          prefix that <emphasis remap="I">netatalk</emphasis> was built with
+          when computing the output for the --cflags and --libs options. This
+          option must be specified before any --libs or --cflags options.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>COPYRIGHT</title>
+
+    <para>Copyright © 1998 Owen Taylor</para>
+
+    <para>Permission to use, copy, modify, and distribute this software and
+    its documentation for any purpose and without fee is hereby granted,
+    provided that the above copyright notice appear in all copies and that
+    both that copyright notice and this permission notice appear in supporting
+    documentation.</para>
+
+    <para>Man page adapted for <command>netatalk-config</command> by Sebastian
+    Rittau in 2001.</para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man1/uniconv.1.xml b/doc/manpages/man1/uniconv.1.xml
new file mode 100644 (file)
index 0000000..8f2d84c
--- /dev/null
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="uniconv.1">
+
+  <refmeta>
+    <refentrytitle>uniconv</refentrytitle>
+
+    <manvolnum>1</manvolnum>
+
+    <refmiscinfo class="date">19 Jan 2013</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>uniconv</refname>
+
+    <refpurpose>convert Netatalk volume encoding</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>uniconv<indexterm><primary>uniconv</primary></indexterm></command>
+
+      <arg choice="opt">-ndv</arg>
+
+      <arg choice="plain">-c <replaceable>cnidbackend</replaceable></arg>
+
+      <arg choice="plain">-f <replaceable>fromcode</replaceable></arg>
+
+      <arg choice="plain">-t <replaceable>tocode</replaceable></arg>
+
+      <arg>-m <replaceable>maccode</replaceable></arg>
+
+      <arg choice="plain"><replaceable>volumepath</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><command>uniconv</command> converts the volume encoding of
+    <replaceable>volumepath</replaceable> from the <replaceable>fromcode</replaceable>
+    to the <replaceable>tocode</replaceable> encoding.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+
+    <variablelist>
+      <varlistentry>
+        <term>-c</term>
+
+        <listitem>
+          <para>CNID backend used on this volume, usually cdb or dbd. Should
+          match the backend selected with afpd for this volume. If not
+          specified, the default CNID backend ":DEFAULT_CNID_SCHEME:" is
+          used</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-d</term>
+
+        <listitem>
+          <para>don't HEX encode leading dots (:2e), equivalent to
+          <option>use dots = yes</option> in <citerefentry><refentrytitle>afp.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-f</term>
+
+        <listitem>
+          <para>encoding to convert from, use ASCII for HEX encoded volumes</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-h</term>
+
+        <listitem>
+          <para>display help</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-m</term>
+
+        <listitem>
+          <para>Macintosh client codepage, required for HEX encoded volumes.
+          Defaults to "MAC_ROMAN"</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-n</term>
+
+        <listitem>
+          <para>"dry run", don't do any real changes</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-t</term>
+
+        <listitem>
+          <para>volume encoding to convert to, e.g. UTF8</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-v</term>
+
+        <listitem>
+          <para>verbose output, use twice for maximum logging.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-V</term>
+
+        <listitem>
+          <para>print version and exit</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+
+    <para></para>
+  </refsect1>
+
+  <refsect1>
+    <title>WARNING</title>
+
+    <para>Setting the wrong options might render your data unusable!!! Make
+    sure you know what you are doing. Always backup your data first.</para>
+
+    <para>It is <emphasis role="bold">*strongly*</emphasis> recommended to do
+    a "dry run" first and to check the output for conversion errors.</para>
+
+    <para><citerefentry><refentrytitle>afpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    should <emphasis>not</emphasis> be running while you change the volume
+    encoding. Remember to change <option>unix charset</option> or
+    <option>vol charset</option> in
+    <citerefentry><refentrytitle>afp.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    to the new codepage, before restarting afpd.</para>
+
+    <para>In case of <emphasis role="bold">MacChineseTraditional</emphasis>,
+    <emphasis role="bold">MacJapanese</emphasis> or
+    <emphasis role="bold">MacKorean</emphasis>,
+    uniconv cannot be used.</para>
+
+    <para><emphasis role="bold">USE AT YOUR OWN RISK!!!</emphasis></para>
+  </refsect1>
+
+  <refsect1>
+    <title>Selectable charsets</title>
+
+    <para>Netatalk provides internal support for UTF-8 (pre- and decomposed)
+    and HEX. If you want to use other charsets, they must be provided by
+    <citerefentry><refentrytitle>iconv</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>
+
+    <para><command>uniconv</command> also knows iso-8859.adapted, an old style
+    1.x NLS widely used. This is only intended for upgrading old volumes,
+    <citerefentry><refentrytitle>afpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    cannot handle iso-8859.adapted anymore.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>CNID background</title>
+
+    <para>The CNID backends maintains name to ID mappings. If you change a
+    filename outside afpd(8) (shell, samba), the CNID db, i.e. the DIDNAME
+    index, gets inconsistent. Netatalk tries to recover from such
+    inconsistencies as gracefully as possible. The mechanisms to resolve such
+    inconsistencies may fail sometimes, though, as this is not an easy task to
+    accomplish. I.e. if several names in the path to the file or directory
+    have changed, things may go wrong.</para>
+
+    <para>If you change a lot of filenames at once, chances are higher that
+    the afpds fallback mechanisms fail, i.e. files will be assigned new IDs,
+    even though the file hasn't changed. <command>uniconv</command>
+    therefore updates the CNID entry for each file/directory directly after it
+    changes the name to avoid inconsistencies. The two supported backends for
+    volumes, dbd and cdb, use the same CNID db format. Therefore, you
+    <emphasis>could</emphasis> use <command>uniconv</command> with cdb and
+    <command>afpd</command> with dbd later.</para>
+
+    <para><emphasis role="bold">Warning</emphasis>: There must not be two
+    processes opening the CNID database using different backends at once! If a
+    volume is still opened with dbd (cnid_metad/cnid_dbd) and you start
+    <command>uniconv</command> with cdb, the result will be a corrupted CNID
+    database, as the two backends use different locking schemes. You might run
+    into additional problems, e.g. if dbd is compiled with transactions, cdb
+    will not update the transaction logs.</para>
+
+    <para>In general, it is recommended to use the same backend for
+    <command>uniconv</command> you are using with
+    <citerefentry><refentrytitle>afpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Examples</title>
+
+    <para>convert 1.x CAP encoded volume to UTF-8, clients used MacRoman
+    codepage, cnidscheme is dbd:</para>
+
+    <screen><prompt>example%</prompt><userinput> uniconv -c dbd -f ASCII -t UTF8 -m MAC_ROMAN /path/to/share</userinput></screen>
+
+    <para>convert iso8859-1 volume to UTF-8, cnidscheme is cdb:</para>
+
+    <screen><prompt>example%</prompt><userinput> uniconv -c cdb -f ISO-8859-1 -t UTF8 -m MAC_ROMAN /path/to/share</userinput></screen>
+
+    <para>convert 1.x volume using iso8859-1 adapted NLS to HEX encoding:</para>
+
+    <screen><prompt>example%</prompt><userinput> uniconv -f ISO-8859-ADAPTED -t ASCII -m MAC_ROMAN/path/to/share</userinput></screen>
+
+    <para>convert UTF-8 volume to HEX, for MacCyrillic clients:</para>
+
+    <screen><prompt>example%</prompt><userinput> uniconv -f UTF8 -t ASCII -m MAC_CYRILLIC /path/to/share</userinput></screen>
+  </refsect1>
+
+  <refsect1>
+    <title>See also</title>
+
+    <para><citerefentry><refentrytitle>afp.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,<citerefentry><refentrytitle>afpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,<citerefentry><refentrytitle>iconv</refentrytitle><manvolnum>1</manvolnum></citerefentry>,<citerefentry><refentrytitle>cnid_metad</refentrytitle><manvolnum>8</manvolnum></citerefentry>,<citerefentry><refentrytitle>cnid_dbd</refentrytitle><manvolnum>8</manvolnum></citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man5/afp.conf.5.xml b/doc/manpages/man5/afp.conf.5.xml
new file mode 100644 (file)
index 0000000..44b5a46
--- /dev/null
@@ -0,0 +1,1960 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="afp.conf.5">
+  <refmeta>
+    <refentrytitle>afp.conf</refentrytitle>
+
+    <manvolnum>5</manvolnum>
+
+    <refmiscinfo class="date">30 Apr 2013</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>afp.conf</refname>
+
+    <refpurpose>Netatalk configuration file <indexterm>
+        <primary>afp.conf</primary>
+      </indexterm></refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>SYNOPSIS</title>
+
+    <para>The <filename>afp.conf</filename> file is the configuration file for
+    the <emphasis role="bold">Netatalk</emphasis> AFP file server.</para>
+
+    <para>All AFP specific configuration and AFP volume definitions are done
+    via this file.</para>
+  </refsect1>
+
+  <refsect1 id="FILEFORMATSECT">
+    <title>FILE FORMAT</title>
+
+    <para>The file consists of sections and parameters. A section begins with
+    the name of the section in square brackets and continues until the next
+    section begins. Sections contain parameters of the form: <programlisting>
+    <replaceable>name</replaceable> = <replaceable>value </replaceable>
+    </programlisting></para>
+
+    <para>The file is line-based - that is, each newline-terminated line
+    represents either a comment, a section name or a parameter.</para>
+
+    <para>Section and parameter names are case sensitive.</para>
+
+    <para>Only the first equals sign in a parameter is significant. Whitespace
+    before or after the first equals sign is discarded. Leading, trailing and
+    internal whitespace in section and parameter names is irrelevant. Leading
+    and trailing whitespace in a parameter value is discarded. Internal
+    whitespace within a parameter value is retained verbatim.</para>
+
+    <para>Any line beginning with a semicolon (<quote>;</quote>) or a hash
+    (<quote>#</quote>) character is ignored, as are lines containing only
+    whitespace.</para>
+
+    <para>Any line ending in a <quote> <literal>\</literal> </quote> is
+    continued on the next line in the customary UNIX fashion.</para>
+
+    <para>The values following the equals sign in parameters are all either a
+    string (no quotes needed) or a boolean, which may be given as yes/no, 1/0
+    or true/false. Case is not significant in boolean values, but is preserved
+    in string values. Some items such as create masks are numeric.</para>
+
+    <para>The parameter <option>include =
+    <replaceable>path</replaceable></option> allows you to include one config
+    file inside another. The file is included literally, as though typed in
+    place. Nested includes are not supported.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>SECTION DESCRIPTIONS</title>
+
+    <para>Each section in the configuration file (except for the [Global]
+    section) describes a shared resource (known as a <quote>volume</quote>).
+    The section name is the name of the volume and the parameters within the
+    section define the volume attributes and options.</para>
+
+    <para>There are two special sections, [Global] and [Homes], which are
+    described under <emphasis>special sections</emphasis>. The following notes
+    apply to ordinary section descriptions.</para>
+
+    <para>A volume consists of a directory to which access is being given plus
+    a description of the access rights which are granted to the user of the
+    service. For volumes the <option>path</option> option must specify the
+    directory to share.</para>
+
+    <para>Any volume section without <option>path</option> option is
+    considered a <emphasis>vol preset</emphasis> which can be selected in
+    other volume sections via the <option>vol preset</option> option and
+    constitutes defaults for the volume. For any option specified both in a
+    preset <emphasis>and</emphasis> in a volume section the volume section
+    setting completely substitutes the preset option.</para>
+
+    <para>The access rights granted by the server are masked by the access
+    rights granted to the specified or guest UNIX user by the host system. The
+    server does not grant more access than the host system grants.</para>
+
+    <para>The following sample section defines an AFP volume. The user has
+    full access to the path <filename>/foo/bar</filename>. The share is
+    accessed via the share name <literal>baz</literal>: <programlisting> [baz]
+    path = /foo/bar </programlisting></para>
+  </refsect1>
+
+  <refsect1>
+    <title>SPECIAL SECTIONS</title>
+
+    <refsect2>
+      <title>The [Global] section</title>
+
+      <para>Parameters in this section apply to the server as a whole.
+      Parameters denoted by a (G) below are must be set in this
+      section.</para>
+    </refsect2>
+
+    <refsect2>
+      <title>The [Homes] section</title>
+
+      <para>This section enable sharing of the UNIX server user home
+      directories. Specifying an optional <option>path</option> parameter
+      means that not the whole user home will be shared but the subdirectory
+      <option>path</option>. It is necessary to define the <option>basedir
+      regex</option> option. It should be a regex which matches the parent
+      directory of the user homes. Parameters denoted by a (H) belong to
+      volume sections. The optional parameter <option>home name</option> can
+      be used to change the AFP volume name which <emphasis>$u's
+      home</emphasis> by default. See below under VARIABLE
+      SUBSTITUTIONS.</para>
+
+      <para>The following example illustrates this. Given all user home
+      directories are stored under <filename>/home</filename>:
+      <programlisting> [Homes]
+      path = afp-data
+      basedir regex = /home</programlisting> For a user
+      <emphasis>john</emphasis> this results in an AFP home volume with a path
+      of <filename>/home/john/afp-data</filename>.</para>
+
+      <para>If <option>basedir regex</option> contains symlink, set the
+      canonicalized absolute path. When <filename>/home</filename> links to
+      <filename>/usr/home</filename>: <programlisting> [Homes]
+      basedir regex = /usr/home</programlisting></para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title>PARAMETERS</title>
+
+    <para>Parameters define the specific attributes of sections.</para>
+
+    <para>Some parameters are specific to the [Global] section (e.g.,
+    <emphasis>log type</emphasis>). All others are permissible only in volume
+    sections. The letter <emphasis>G</emphasis> in parentheses indicates that
+    a parameter is specific to the [Global] section. The letter
+    <emphasis>V</emphasis> indicates that a parameter can be specified in a
+    volume specific section.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>VARIABLE SUBSTITUTIONS</title>
+
+    <para>You can use variables in volume names. The use of variables in paths
+    is not supported for now.</para>
+
+    <orderedlist>
+      <listitem>
+        <para>if you specify an unknown variable, it will not get
+        converted.</para>
+      </listitem>
+
+      <listitem>
+        <para>if you specify a known variable, but that variable doesn't have
+        a value, it will get ignored.</para>
+      </listitem>
+    </orderedlist>
+
+    <para>The variables which can be used for substitutions are:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term>$b</term>
+
+        <listitem>
+          <para>basename</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$c</term>
+
+        <listitem>
+          <para>client's ip address</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$d</term>
+
+        <listitem>
+          <para>volume pathname on server</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$f</term>
+
+        <listitem>
+          <para>full name (contents of the gecos field in the passwd
+          file)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$g</term>
+
+        <listitem>
+          <para>group name</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$h</term>
+
+        <listitem>
+          <para>hostname</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$i</term>
+
+        <listitem>
+          <para>client's ip, without port</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$s</term>
+
+        <listitem>
+          <para>server name (this can be the hostname)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$u</term>
+
+        <listitem>
+          <para>user name (if guest, it is the user that guest is running
+          as)</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$v</term>
+
+        <listitem>
+          <para>volume name</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>$$</term>
+
+        <listitem>
+          <para>prints dollar sign ($)</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>EXPLANATION OF GLOBAL PARAMETERS</title>
+
+    <refsect2>
+      <title>Authentication Options</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>ad domain = <parameter>DOMAIN</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Append @DOMAIN to username when authenticating. Useful in
+            Active Directory environments that otherwise would require the
+            user to enter the full user@domain string.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>admin auth user = <parameter>user</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifying eg "<option>admin auth user = root</option>"
+            whenever a normal user login fails, afpd will try to authenticate
+            as the specified <option>admin auth user</option>. If this
+            succeeds, a normal session is created for the original connecting
+            user. Said differently: if you know the password of <option>admin
+            auth user</option>, you can authenticate as any other user.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>k5 keytab = <replaceable>path</replaceable>
+          <type>(G)</type></term>
+
+          <term>k5 service = <replaceable>service</replaceable>
+          <type>(G)</type></term>
+
+          <term>k5 realm = <replaceable>realm</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>These are required if the server supports the Kerberos 5
+            authentication UAM.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>nt domain = <parameter>DOMAIN</parameter>
+          <type>(G)</type></term>
+
+          <term>nt separator = <parameter>SEPARATOR</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Use for eg. winbind authentication, prepends both strings
+            before the username from login and then tries to authenticate with
+            the result through the available and active UAM authentication
+            modules.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>save password = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Enables or disables the ability of clients to save passwords
+            locally.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>set password = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Enables or disables the ability of clients to change their
+            passwords via chooser or the "connect to server" dialog.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>uam list = <replaceable>uam list</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Space or comma separated list of UAMs. (The default is
+            "uams_dhx.so uams_dhx2.so").</para>
+
+            <para>The most commonly used UAMs are:</para>
+
+            <variablelist>
+              <varlistentry>
+                <term>uams_guest.so</term>
+
+                <listitem>
+                  <para>allows guest logins</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>uams_clrtxt.so</term>
+
+                <listitem>
+                  <para>(uams_pam.so or uams_passwd.so) Allow logins with
+                  passwords transmitted in the clear. (legacy)</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>uams_randum.so</term>
+
+                <listitem>
+                  <para>allows Random Number and Two-Way Random Number
+                  Exchange for authentication (requires a separate file
+                  containing the passwords, either :ETCDIR:/afppasswd file or
+                  the one specified via "<option>passwd file</option>". See
+                  <citerefentry>
+                      <refentrytitle>afppasswd</refentrytitle>
+
+                      <manvolnum>1</manvolnum>
+                    </citerefentry> for details. (legacy)</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>uams_dhx.so</term>
+
+                <listitem>
+                  <para>(uams_dhx_pam.so or uams_dhx_passwd.so) Allow
+                  Diffie-Hellman eXchange (DHX) for authentication.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>uams_dhx2.so</term>
+
+                <listitem>
+                  <para>(uams_dhx2_pam.so or uams_dhx2_passwd.so) Allow
+                  Diffie-Hellman eXchange 2 (DHX2) for authentication.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>uam_gss.so</term>
+
+                <listitem>
+                  <para>Allow Kerberos V for authentication (optional)</para>
+                </listitem>
+              </varlistentry>
+            </variablelist>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>uam path = <replaceable>path</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Sets the default path for UAMs for this server (default is
+            :LIBDIR:/netatalk).</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Charset Options</title>
+
+      <para>With OS X Apple introduced the AFP3 protocol. One of the big
+      changes was, that AFP3 uses Unicode names encoded as Decomposed UTF-8
+      (UTF8-MAC). Previous AFP/OS versions used charsets like MacRoman,
+      MacCentralEurope, etc.</para>
+
+      <para>To be able to serve AFP3 and older clients at the same time,
+      <command>afpd</command> needs to be able to convert between UTF-8 and
+      Mac charsets. Even OS X clients partly still rely on the mac charset. As
+      there's no way, <command>afpd</command> can detect the codepage a pre
+      AFP3 client uses, you have to specify it using the <option>mac
+      charset</option> option. The default is MacRoman, which should be fine
+      for most western users.</para>
+
+      <para>As <command>afpd</command> needs to interact with UNIX operating
+      system as well, it need's to be able to convert from UTF8-MAC / Mac
+      charset to the UNIX charset. By default <command>afpd</command> uses
+      <emphasis>UTF8</emphasis>. You can set the UNIX charset using the
+      <option>unix charset</option> option. If you're using extended
+      characters in the configuration files for <command>afpd</command>, make
+      sure your terminal matches the <option>unix charset</option>.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term>mac charset = <parameter>CHARSET</parameter>
+          <type>(G)/(V)</type></term>
+
+          <listitem>
+            <para>Specifies the Mac clients charset, e.g.
+            <emphasis>MAC_ROMAN</emphasis>. This is used to convert strings
+            and filenames to the clients codepage for OS9 and Classic, i.e.
+            for authentication and AFP messages (SIGUSR2 messaging). This will
+            also be the default for the volumes <option>mac charset</option>.
+            Defaults to <emphasis>MAC_ROMAN</emphasis>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>unix charset = <parameter>CHARSET</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifies the servers unix charset, e.g.
+            <emphasis>ISO-8859-15</emphasis> or <emphasis>EUC-JP</emphasis>.
+            This is used to convert strings to/from the systems locale, e.g.
+            for authentication, server messages and volume names. If
+            <emphasis>LOCALE</emphasis> is set, the systems locale is used.
+            Defaults to <emphasis>UTF8</emphasis>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>vol charset = <parameter>CHARSET</parameter>
+          <type>(G)/(V)</type></term>
+
+          <listitem>
+            <para>Specifies the encoding of the volumes filesystem. By
+            default, it is the same as <option>unix charset</option>.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Password Options</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>passwd file = <parameter>path</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Sets the path to the Randnum UAM passwd file for this server
+            (default is :ETCDIR:/afppasswd).</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>passwd minlen = <parameter>number</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Sets the minimum password length, if supported by the
+            UAM</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Network Options</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>advertise ssh = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Allows old Mac OS X clients (10.3.3-10.4) to automagically
+            establish a tunneled AFP connection through SSH. If this option is
+            set, the server's answers to client's FPGetSrvrInfo requests
+            contain an additional entry. It depends on both client's settings
+            and a correctly configured and running <citerefentry>
+                <refentrytitle>sshd</refentrytitle>
+
+                <manvolnum>8</manvolnum>
+              </citerefentry> on the server to let things work.</para>
+
+            <note>
+              <para>Setting this option is not recommended since globally
+              encrypting AFP connections via SSH will increase the server's
+              load significantly. On the other hand, Apple's client side
+              implementation of this feature in MacOS X versions prior to
+              10.3.4 contained a security flaw.</para>
+            </note>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>afp listen = <replaceable>ip address[:port] [ip address[:port]
+          ...]</replaceable> <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifies the IP address that the server should advertise
+            <emphasis role="bold">and</emphasis> listens to. The default is
+            advertise the first IP address of the system, but to listen for
+            any incoming request. The network address may be specified either
+            in dotted-decimal format for IPv4 or in hexadecimal format for
+            IPv6.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>afp port = <replaceable>port number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Allows a different TCP port to be used for AFP. The default
+            is 548. Also sets the default port applied when none specified in
+            an <option>afp listen</option> option.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>cnid listen = <replaceable>ip address[:port] [ip
+          address[:port] ...]</replaceable> <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifies the IP address that the CNID server should listen
+            on. The default is <emphasis
+            role="bold">localhost:4700</emphasis>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>disconnect time = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Keep disconnected AFP sessions for
+            <parameter>number</parameter> hours before dropping them. Default
+            is 24 hours.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>dsireadbuf = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Scale factor that determines the size of the DSI/TCP
+            readahead buffer, default is 12. This is multiplies with the DSI
+            server quantum (default ~300k) to give the size of the buffer.
+            Increasing this value might increase throughput in fast local
+            networks for volume to volume copies. <emphasis>Note</emphasis>:
+            This buffer is allocated per afpd child process, so specifying
+            large values will eat up large amount of memory (buffer size *
+            number of clients).</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>fqdn = <replaceable>name:port</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifies a fully-qualified domain name, with an optional
+            port. This is discarded if the server cannot resolve it. This
+            option is not honored by AppleShare clients &lt;= 3.8.3. This
+            option is disabled by default. Use with caution as this will
+            involve a second name resolution step on the client side. Also
+            note that afpd will advertise this name:port combination but not
+            automatically listen to it.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>hostname = <replaceable>name</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Use this instead of the result from calling hostname for
+            determining which IP address to advertise, therefore the hostname
+            is resolved to an IP which is the advertised. This is NOT used for
+            listening and it is also overwritten by <option>afp
+            listen</option>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>max connections = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Sets the maximum number of clients that can simultaneously
+            connect to the server (default is 200).</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>server quantum = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>This specifies the DSI server quantum. The default value is
+            1 MB. The maximum value is 0xFFFFFFFFF, the minimum is 32000. If
+            you specify a value that is out of range, the default value will
+            be set. Do not change this value unless you're absolutely sure,
+            what you're doing</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>sleep time = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Keep sleeping AFP sessions for <parameter>number</parameter>
+            hours before disconnecting clients in sleep mode. Default is 10
+            hours.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>tcprcvbuf = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Try to set TCP receive buffer using setsockpt(). Often OSes
+            impose restrictions on the applications ability to set this
+            value.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>tcpsndbuf = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Try to set TCP send buffer using setsockpt(). Often OSes
+            impose restrictions on the applications ability to set this
+            value.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>use sendfile = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Whether to use sendfile<indexterm>
+                <primary>sendfile</primary>
+              </indexterm> syscall for sending file data to clients.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>zeroconf = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Whether to use automatic Zeroconf<indexterm>
+                <primary>Zeroconf</primary>
+
+                <secondary>Bonjour</secondary>
+              </indexterm> service registration if Avahi or mDNSResponder were
+            compiled in.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Miscellaneous Options</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>admin group = <replaceable>group</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Allows users of a certain group to be seen as the superuser
+            when they log in. This option is disabled by default.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>afp read locks = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Whether to apply locks to the byte region read in FPRead
+            calls. The AFP spec mandates this, but it's not really in line
+            with UNIX semantics and is a performance hug.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>afpstats = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Whether to provide AFP runtime statistics (connected
+            users, open volumes) via dbus.</para>            
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>basedir regex = <replaceable>regex</replaceable>
+          <type>(H)</type></term>
+
+          <listitem>
+            <para>Regular expression which matches the parent directory of the
+            user homes. If <option>basedir regex</option> contains symlink,
+            you must set the canonicalized absolute path. In the simple case
+            this is just a path ie <option>basedir regex =
+            /home</option></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>close vol = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Whether to close volumes possibly opened by clients when
+            they're removed from the configuration and the configuration is
+            reloaded.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>cnid server = <replaceable>ipaddress[:port]</replaceable>
+          <type>(G)/(V)</type></term>
+
+          <listitem>
+            <para>Specifies the IP address and port of a cnid_metad server,
+            required for CNID dbd backend. Defaults to localhost:4700. The
+            network address may be specified either in dotted-decimal format
+            for IPv4 or in hexadecimal format for IPv6.-</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>dircachesize = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Maximum possible entries in the directory cache. The cache
+            stores directories and files. It is used to cache the full path to
+            directories and CNIDs which considerably speeds up directory
+            enumeration.</para>
+
+            <para>Default size is 8192, maximum size is 131072. Given value is
+            rounded up to nearest power of 2. Each entry takes about 100
+            bytes, which is not much, but remember that every afpd child
+            process for every connected user has its cache.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>extmap file = <parameter>path</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Sets the path to the file which defines file extension
+            type/creator mappings. (default is :ETCDIR:/extmap.conf).</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>guest account = <replaceable>name</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifies the user that guests should use (default is
+            "nobody"). The name should be quoted.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>home name = <replaceable>name</replaceable>
+          <type>(H)</type></term>
+
+          <listitem>
+            <para>AFP user home volume name. The default is <emphasis>user's
+            home</emphasis>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>login message = <replaceable>message</replaceable>
+          <type>(G)/(V)</type></term>
+
+          <listitem>
+            <para>Sets a message to be displayed when clients logon to the
+            server. The message should be in <option>unix charset</option> and
+            should be quoted. Extended characters are allowed.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>mimic model = <replaceable>model</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifies the icon model that appears on clients. Defaults
+            to off. Note that afpd must support Zeroconf.
+            Examples: RackMac (same as Xserve), PowerBook, PowerMac,
+            Macmini, iMac, MacBook, MacBookPro, MacBookAir, MacPro,
+            AppleTV1,1, AirPort.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>signature = &lt;text&gt; <type>(G)</type></term>
+
+          <listitem>
+            <para>Specify a server signature. The maximum length is 16
+            characters. This option is useful for clustered environments, to
+            provide fault isolation etc. By default, afpd generate signature
+            and saving it to
+            <filename>:STATEDIR:/netatalk/afp_signature.conf</filename>
+            automatically (based on random number). See also
+            asip-status.pl(1).</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>solaris share reservations =
+          <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Use share reservations on Solaris. Solaris CIFS server uses
+            this too, so this makes a lock coherent multi protocol
+            server.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>vol dbpath = <replaceable>path</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Sets the database information to be stored in path. You have
+            to specify a writable location, even if the volume is read only.
+            The default is
+            <filename>:STATEDIR:/netatalk/CNID/</filename>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>volnamelen = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Max length of UTF8-MAC volume name for Mac OS X. Note that
+            Hangul is especially sensitive to this.</para>
+
+            <para><programlisting> 73: limit of Mac OS X 10.1 80: limit of Mac
+            OS X 10.4/10.5 (default) 255: limit of recent Mac OS
+            X</programlisting> Mac OS 9 and earlier are not influenced by
+            this, because Maccharset volume name is always limited to 27
+            bytes.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>vol preset = <replaceable>name</replaceable>
+          <type>(G)/(V)</type></term>
+
+          <listitem>
+            <para>Use section <option>name</option> as option preset for all
+            volumes (when set in the [Global] section) or for one volume (when
+            set in that volume's section).</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Logging Options</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>log file = <replaceable>logfile</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>If not specified Netatalk logs to syslogs daemon facility.
+            Otherwise it logs to <option>logfile</option>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>log level = <replaceable>type:level [type:level
+          ...]</replaceable> <type>(G)</type></term>
+
+          <term>log level = <replaceable>type:level,[type:level,
+          ...]</replaceable> <type>(G)</type></term>
+
+          <listitem>
+            <para>Specify that any message of a loglevel up to the given
+            <option>log level</option> should be logged.</para>
+
+            <para>By default afpd logs to syslog with a default logging setup
+            equivalent to <option>default:note</option></para>
+
+            <para>logtypes: default, afpdaemon, logger, uamsdaemon</para>
+
+            <para>loglevels: severe, error, warn, note, info, debug, debug6,
+            debug7, debug8, debug9, maxdebug</para>
+
+            <note>
+              <para>Both logtype and loglevels are case insensitive.</para>
+            </note>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2 id="fceconf">
+      <title>Filesystem Change Events (FCE<indexterm>
+          <primary>FCE</primary>
+        </indexterm>)</title>
+
+      <para>Netatalk includes a nifty filesystem change event mechanism where
+      afpd processes notify interested listeners about certain filesystem
+      event by UDP network datagrams.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term>fce listener = <replaceable>host[:port]</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Enables sending FCE events to the specified
+            <parameter>host</parameter>, default <parameter>port</parameter>
+            is 12250 if not specified. Specifying multiple listeners is done
+            by having this option once for each of them.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>fce events =
+          <replaceable>fmod,fdel,ddel,fcre,dcre,tmsz</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Specifies which FCE events are active, default is
+            <parameter>fmod,fdel,ddel,fcre,dcre</parameter>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>fce coalesce = <replaceable>all|delete|create</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Coalesce FCE events.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>fce holdfmod = <replaceable>seconds</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>This determines the time delay in seconds which is always
+            waited if another file modification for the same file is done by a
+            client before sending an FCE file modification event (fmod). For
+            example saving a file in Photoshop would generate multiple events
+            by itself because the application is opening, modifying and
+            closing a file multiple times for every "save". Default: 60
+            seconds.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Debug Parameters</title>
+
+      <para>These options are useful for debugging only.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term>tickleval = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Sets the tickle timeout interval (in seconds). Defaults to
+            30.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>timeout = <replaceable>number</replaceable>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Specify the number of tickles to send before timing out a
+            connection. The default is 4, therefore a connection will timeout
+            after 2 minutes.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>client polling = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>With this option enabled, afpd won't advertise that it is
+            capable of server notifications, so that connected clients poll
+            the server every 10 seconds to detect changes in opened server
+            windows. <emphasis>Note</emphasis>: Depending on the number of
+            simultaneously connected clients and the network's speed, this can
+            lead to a significant higher load on your network!</para>
+
+            <para>Do not use this option any longer as present Netatalk
+            correctly supports server notifications, allowing connected
+            clients to update folder listings in case another client changed
+            the contents.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2 id="acl_options">
+      <title>Options for ACL handling</title>
+
+      <para>By default, the effective permission of the authenticated user are
+      only mapped to the mentioned UARights permission structure, not the UNIX
+      mode. You can adjust this behaviour with the configuration option
+      <option>mac acls</option>:</para>
+
+      <variablelist id="mac_acls">
+        <varlistentry>
+          <term>map acls = <parameter>none|rights|mode</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para><variablelist>
+                <varlistentry>
+                  <term>none</term>
+
+                  <listitem>
+                    <para>no mapping of ACLs </para>
+                  </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                  <term>rights</term>
+
+                  <listitem>
+                    <para>effective permissions are mapped to UARights
+                    structure. This is the default.</para>
+                  </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                  <term>mode</term>
+
+                  <listitem>
+                    <para>ACLs are additionally mapped to the UNIX mode of the
+                    filesystem object.</para>
+                  </listitem>
+                </varlistentry>
+              </variablelist></para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+
+      <para>If you want to be able to display ACLs on the client, you must
+      setup both client and server as part on a authentication domain
+      (directory service, eg LDAP, Open Directory, Active Directory). The
+      reason is, in OS X ACLs are bound to UUIDs, not just uid's or gid's.
+      Therefor Netatalk must be able to map every filesystem uid and gid to a
+      UUID so that it can return the server side ACLs which are bound to UNIX
+      uid and gid mapped to OS X UUIDs.</para>
+
+      <para>Netatalk can query a directory server using LDAP queries. Either
+      the directory server already provides an UUID attribute for user and
+      groups (Active Directory, Open Directory) or you reuse an unused
+      attribute (or add a new one) to you directory server (eg
+      OpenLDAP).</para>
+
+      <para>The following LDAP options must be configured for Netatalk:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term>ldap auth method = <parameter>none|simple|sasl</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Authentication method: <option>none | simple |
+            sasl</option></para>
+
+            <para><variablelist>
+                <varlistentry>
+                  <term>none</term>
+
+                  <listitem>
+                    <para>anonymous LDAP bind</para>
+                  </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                  <term>simple</term>
+
+                  <listitem>
+                    <para>simple LDAP bind</para>
+                  </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                  <term>sasl</term>
+
+                  <listitem>
+                    <para>SASL. Not yet supported !</para>
+                  </listitem>
+                </varlistentry>
+              </variablelist></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap auth dn = <parameter>dn</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Distinguished Name of the user for simple bind.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap auth pw = <parameter>password</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Distinguished Name of the user for simple bind.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap server = <parameter>host</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Name or IP address of your LDAP Server. This is only needed
+            for explicit ACL support in order to be able to query LDAP for
+            UUIDs.</para>
+
+            <para>You can use <citerefentry>
+                <refentrytitle>afpldaptest</refentrytitle>
+
+                <manvolnum>1</manvolnum>
+              </citerefentry> to syntactically check your config.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap userbase = <parameter>base dn</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>DN of the user container in LDAP.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap userscope = <parameter>scope</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Search scope for user search: <option>base | one |
+            sub</option></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap groupbase = <parameter>base dn</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>DN of the group container in LDAP.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap groupscope = <parameter>scope</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Search scope for user search: <option>base | one |
+            sub</option></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap uuid attr = <parameter>dn</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Name of the LDAP attribute with the UUIDs.</para>
+
+            <para>Note: this is used both for users and groups.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap name attr = <parameter>dn</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Name of the LDAP attribute with the users short name.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap uuid string = <parameter>STRING</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Format of the uuid string in the directory. A series of x
+            and -, where every x denotes a value 0-9a-f and every - is a
+            separator.</para>
+
+            <para>Default: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap uuid encoding = <parameter>string | ms-guid (default:
+          string)</parameter> <type>(G)</type></term>
+
+          <listitem>
+            <para>Format of the UUID of the LDAP attribute, allows usage of
+            the binary objectGUID fields from Active Directory. If left
+            unspecified, string is the default, which passes through the ASCII
+            UUID returned by most other LDAP stores. If set to ms-guid, the
+            internal UUID representation is converted to and from the binary
+            format used in the objectGUID attribute found on objects in Active
+            Directory when interacting with the server.</para>
+
+            <para><variablelist>
+                <varlistentry>
+                  <term>string</term>
+
+                  <listitem>
+                    <para>UUID is a string, use with eg OpenDirectory.</para>
+                  </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                  <term>ms-guid</term>
+
+                  <listitem>
+                    <para>Binary objectGUID from Active Directory</para>
+                  </listitem>
+                </varlistentry>
+              </variablelist></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ldap group attr = <parameter>dn</parameter>
+          <type>(G)</type></term>
+
+          <listitem>
+            <para>Name of the LDAP attribute with the groups short
+            name.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title>EXPLANATION OF VOLUME PARAMETERS</title>
+
+    <refsect2>
+      <title>Parameters</title>
+
+      <para>The section name defines the volume name.
+      No two volumes may have the same
+      name. The volume name cannot contain the <keycode>':'</keycode>
+      character. The volume name is mangled if it is very long. Mac charset
+      volume name is limited to 27 characters. UTF8-MAC volume name is limited
+      to volnamelen parameter.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term>path = <replaceable>PATH</replaceable> <type>(V)</type></term>
+
+          <listitem>
+            <para>The path name must be a fully qualified path name.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>appledouble = <replaceable>ea|v2</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>Specify the format of the metadata files, which are used for
+            saving Mac resource fork as well. Earlier versions used
+            AppleDouble v2, the new default format is <emphasis
+            role="bold">ea</emphasis>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>vol size limit = <replaceable>size in MiB</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>Useful for Time Machine: limits the reported volume size,
+            thus preventing Time Machine from using the whole real disk space
+            for backup. Example: "vol size limit = 1000" would limit the
+            reported disk space to 1 GB. <emphasis role="bold">IMPORTANT:
+            </emphasis> This is an approximated calculation taking into
+            account the contents of Time Machine sparsebundle images. Therefor
+            you MUST NOT use this volume to store other content when using
+            this option, because it would NOT be accounted. The calculation
+            works by reading the band size from the Info.plist XML file of the
+            sparsebundle, reading the bands/ directory counting the number of
+            band files, and then multiplying one with the other.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>valid users = <replaceable>user @group</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>The allow option allows the users and groups that access a
+            share to be specified. Users and groups are specified, delimited
+            by spaces or commas. Groups are designated by a @ prefix. Names
+            may be quoted in order to allow for spaces in names. Example:
+            <programlisting>valid users = user "user 2" @group “@group 2"</programlisting></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>invalid users = <replaceable>users/groups</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>The deny option specifies users and groups who are not
+            allowed access to the share. It follows the same format as the
+            "valid users" option.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>hosts allow = <replaceable>IP host address/IP netmask bits [
+          ... ]</replaceable> <type>(V)</type></term>
+
+          <listitem>
+            <para>Only listed hosts and networks are allowed, all others are
+            rejected. The network address may be specified either in
+            dotted-decimal format for IPv4 or in hexadecimal format for
+            IPv6.</para>
+
+            <para>Example: hosts allow = 10.1.0.0/16 10.2.1.100
+            2001:0db8:1234::/48</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>hosts deny = <replaceable>IP host address/IP netmask bits [
+          ... ]</replaceable> <type>(V)</type></term>
+
+          <listitem>
+            <para>Listed hosts and nets are rejected, all others are
+            allowed.</para>
+
+            <para>Example: hosts deny = 192.168.100/24 10.1.1.1
+            2001:db8::1428:57ab</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>cnid scheme = <replaceable>backend</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>set the CNID backend to be used for the volume, default is
+            [:DEFAULT_CNID_SCHEME:] available schemes:
+            [:COMPILED_BACKENDS:]</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>ea = <replaceable>none|auto|sys|ad</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>Specify how Extended Attributes<indexterm>
+                <primary>Extended Attributes</primary>
+              </indexterm> are stored. <option>auto</option> is the
+            default.</para>
+
+            <variablelist>
+              <varlistentry>
+                <term>auto</term>
+
+                <listitem>
+                  <para>Try <option>sys</option> (by setting an EA on the
+                  shared directory itself), fallback to <option>ad</option>.
+                  Requires writable volume for performing test. "<option>read
+                  only = yes</option>" overwrites <option>auto</option> with
+                  <option>none</option>. Use explicit "<option>ea =
+                  sys|ad</option>" for read-only volumes where
+                  appropriate.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>sys</term>
+
+                <listitem>
+                  <para>Use filesystem Extended Attributes.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>ad</term>
+
+                <listitem>
+                  <para>Use files in <emphasis>.AppleDouble</emphasis>
+                  directories.</para>
+                </listitem>
+              </varlistentry>
+
+              <varlistentry>
+                <term>none</term>
+
+                <listitem>
+                  <para>No Extended Attributes support.</para>
+                </listitem>
+              </varlistentry>
+            </variablelist>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>mac charset = <replaceable>CHARSET</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>specifies the Mac client charset for this Volume, e.g.
+            <emphasis>MAC_ROMAN</emphasis>, <emphasis>MAC_CYRILLIC</emphasis>.
+            If not specified the global setting is applied. This setting is
+            only required if you need volumes, where the Mac charset differs
+            from the one globally set in the [Global] section.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>casefold = <option>option</option> <type>(V)</type></term>
+
+          <listitem>
+            <para>The casefold option handles, if the case of filenames should
+            be changed. The available options are:</para>
+
+            <para><option>tolower</option> - Lowercases names in both
+            directions.</para>
+
+            <para><option>toupper</option> - Uppercases names in both
+            directions.</para>
+
+            <para><option>xlatelower</option> - Client sees lowercase, server
+            sees uppercase.</para>
+
+            <para><option>xlateupper</option> - Client sees uppercase, server
+            sees lowercase.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>password = <replaceable>password</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>This option allows you to set a volume password, which can
+            be a maximum of 8 characters long (using ASCII strongly
+            recommended at the time of this writing).</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>file perm = <replaceable>mode</replaceable>
+          <type>(V)</type></term>
+
+          <term>directory perm = <replaceable>mode</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>Add(or) with the client requested permissions: <option>file
+            perm</option> is for files only, <option>directory perm</option>
+            is for directories only. Don't use with "<option>unix priv =
+            no</option>".</para>
+
+            <example>
+              <title>Volume for a collaborative workgroup</title>
+
+              <para><programlisting>file perm = 0660 directory perm =
+              0770</programlisting></para>
+            </example>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>umask = <replaceable>mode</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>set perm mask. Don't use with "<option>unix priv =
+            no</option>".</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>preexec = <replaceable>command</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>command to be run when the volume is mounted, ignored for
+            user defined volumes</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>postexec = <replaceable>command</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>command to be run when the volume is closed, ignored for
+            user defined volumes</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>root preexec = <replaceable>command</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>command to be run as root when the volume is mounted,
+            ignored for user defined volumes</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>root postexec = <replaceable>command</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>command to be run as root when the volume is closed, ignored
+            for user defined volumes</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>rolist = <option>users/groups</option> <type>(V)</type></term>
+
+          <listitem>
+            <para>Allows certain users and groups to have read-only access to
+            a share. This follows the allow option format.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>rwlist = <replaceable>users/groups</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>Allows certain users and groups to have read/write access to
+            a share. This follows the allow option format.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>veto files = <replaceable>vetoed names</replaceable>
+          <type>(V)</type></term>
+
+          <listitem>
+            <para>hide files and directories,where the path matches one of the
+            '/' delimited vetoed names. The veto string must always be
+            terminated with a '/', eg. "veto1/", "veto1/veto2/".</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
+      <title>Volume options</title>
+
+      <para>Boolean volume options.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term>acls = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Whether to flag volumes as supporting ACLs. If ACL support
+            is compiled in, this is yes by default.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>cnid dev = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Whether to use the device number in the CNID backends. Helps
+            when the device number is not constant across a reboot, eg
+            cluster, ...</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>convert appledouble = <replaceable>BOOLEAN</replaceable>
+          (default: <emphasis>yes</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Whether automatic conversion from <option>appledouble =
+            v2</option> to <option>appledouble = ea</option> is performed when
+            accessing filesystems from clients. This is generally useful, but
+            costs some performance. It's recommendable to run
+            <command>dbd</command> on volumes and do the conversion with that.
+            Then this option can be set to no.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>follow symlinks = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>The default setting is false thus symlinks are not followed
+            on the server. This is the same behaviour as OS X's AFP server.
+            Setting the option to true causes afpd to follow symlinks on the
+            server. symlinks may point outside of the AFP volume, currently
+            afpd doesn't do any checks for "wide symlinks".</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>invisible dots = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>make dot files invisible. WARNING: enabling this option will
+              lead to unwanted sideeffects were OS X applications when saving
+              files to a temporary file starting with a dot first, then renaming
+              the temp file to its final name, result in the saved file being
+              invisible. The only thing this option is useful for is making
+              files that start with a dot invisible on Mac OS 9. It's
+              completely useless on Mac OS X, as both in Finder and in Terminal
+              files starting with a dot are hidden anyway.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>network ids = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Whether the server support network ids. Setting this to
+            <emphasis>no</emphasis> will result in the client not using ACL
+            AFP functions.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>preexec close = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>A non-zero return code from preexec close the volume being
+            immediately, preventing clients to mount/see the volume in
+            question.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>read only = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Specifies the share as being read only for all users.
+            Overwrites <option>ea = auto</option> with <option>ea =
+            none</option></para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>root preexec close= <replaceable>BOOLEAN</replaceable>
+          (default: <emphasis>no</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>A non-zero return code from root_preexec closes the volume
+            immediately, preventing clients to mount/see the volume in
+            question.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>search db = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Use fast CNID database namesearch instead of slow recursive
+            filesystem search. Relies on a consistent CNID database, ie Samba
+            or local filesystem access lead to inaccurate or wrong results.
+            Works only for "dbd" CNID db volumes.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>stat vol = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Whether to stat volume path when enumerating volumes list,
+            useful for automounting or volumes created by a preexec
+            script.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>time machine = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Whether to enable Time Machine support for this
+            volume.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>unix priv = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>yes</emphasis>) <type>(V)</type></term>
+
+          <listitem>
+            <para>Whether to use AFP3 UNIX privileges. This should be set for
+            OS X clients. See also: <option>file perm</option>,
+            <option>directory perm</option> and <option>umask</option>.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title>CNID backends</title>
+
+    <para>The AFP protocol mostly refers to files and directories by ID and
+    not by name. Netatalk needs a way to store these ID's in a persistent way,
+    to achieve this several different CNID backends are available. The CNID
+    Databases are by default located in the
+    <filename>:STATEDIR:/netatalk/CNID/(volumename)/.AppleDB/</filename>
+    directory.</para>
+
+    <variablelist>
+      <varlistentry>
+        <term>cdb</term>
+
+        <listitem>
+          <para>"Concurrent database", backend is based on Oracle Berkley DB.
+          With this backend several <command>afpd</command> daemons access the
+          CNID database directly. Berkeley DB locking is used to synchronize
+          access, if more than one <command>afpd</command> process is active
+          for a volume. The drawback is, that the crash of a single
+          <command>afpd</command> process might corrupt the database.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>dbd</term>
+
+        <listitem>
+          <para>Access to the CNID database is restricted to the
+          <command>cnid_metad</command> daemon process.
+          <command>afpd</command> processes communicate with the daemon for
+          database reads and updates. If built with Berkeley DB transactions
+          the probability for database corruption is practically zero, but
+          performance can be slower than with <option>cdb</option></para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>last</term>
+
+        <listitem>
+          <para>This backend is an exception, in terms of ID persistency. ID's
+          are only valid for the current session. This is basically what
+          <command>afpd</command> did in the 1.5 (and 1.6) versions. This
+          backend is still available, as it is useful for e.g. sharing cdroms.
+          Starting with Netatalk 3.0, it becomes the <emphasis>read only
+          mode</emphasis> automatically.</para>
+
+          <para><emphasis role="bold">Warning</emphasis>: It is
+          <emphasis>NOT</emphasis> recommended to use this backend for volumes
+          anymore, as <command>afpd</command> now relies heavily on a
+          persistent ID database. Aliases will likely not work and filename
+          mangling is not supported.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+
+    <para>Even though <command>./configure --help</command> might show that
+    there are other CNID backends available, be warned those are likely broken
+    or mainly used for testing. Don't use them unless you know what you're
+    doing, they may be removed without further notice from future
+    versions.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Charset options</title>
+
+    <para>With OS X Apple introduced the AFP3 protocol. One of the most
+    important changes was that AFP3 uses unicode names encoded as UTF-8
+    decomposed. Previous AFP/OS versions used codepages, like MacRoman,
+    MacCentralEurope, etc.</para>
+
+    <para><command>afpd</command> needs a way to preserve extended Macintosh
+    characters, or characters illegal in unix filenames, when saving files on
+    a unix filesystem. Earlier versions used the the so called CAP encoding.
+    An extended character (&gt;0x7F) would be converted to a :xx sequence,
+    e.g. the Apple Logo (MacRoman: 0xF0) was saved as <literal>:f0</literal>.
+    Some special characters will be converted as to :xx notation as well.
+    '<keycode>/</keycode>' will be encoded to <literal>:2f</literal>, if
+    <option>usedots</option> is not specified, a leading dot
+    '<keycode>.</keycode>' will be encoded as <literal>:2e</literal>.</para>
+
+    <para>This version now uses UTF-8 as the default encoding for names.
+    '<keycode>/</keycode>' will be converted to '<keycode>:</keycode>'.</para>
+
+    <para>The <option>vol charset</option> option will allow you to select
+    another volume encoding. E.g. for western users another useful setting
+    could be vol charset ISO-8859-15. <command>afpd</command> will accept any
+    <citerefentry>
+        <refentrytitle><command>iconv</command></refentrytitle>
+
+        <manvolnum>1</manvolnum>
+      </citerefentry> provided charset. If a character cannot be converted
+    from the <option>mac charset</option> to the selected <option>vol
+    charset</option>, afpd will save it as a CAP encoded character. For AFP3
+    clients, <command>afpd</command> will convert the UTF-8<indexterm>
+        <primary>UTF8</primary>
+
+        <secondary>afpd's vol charset setting</secondary>
+      </indexterm><indexterm>
+        <primary>UTF8-MAC</primary>
+
+        <secondary>afpd's vol charset setting</secondary>
+      </indexterm><indexterm>
+        <primary>ISO-8859-15</primary>
+
+        <secondary>afpd's vol charset setting</secondary>
+      </indexterm><indexterm>
+        <primary>ISO-8859-1</primary>
+
+        <secondary>afpd's vol charset setting</secondary>
+      </indexterm> character to <option>mac charset</option> first. If this
+    conversion fails, you'll receive a -50 error on the mac.</para>
+
+    <para><emphasis>Note</emphasis>: Whenever you can, please stick with the
+    default UTF-8 volume format.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para><citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afppasswd</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp_signature.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>extmap.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>cnid_metad</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man5/afp_signature.conf.5.xml b/doc/manpages/man5/afp_signature.conf.5.xml
new file mode 100644 (file)
index 0000000..a5ed793
--- /dev/null
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="afp_signature.conf.5">
+
+  <refmeta>
+    <refentrytitle>afp_signature.conf</refentrytitle>
+
+    <manvolnum>5</manvolnum>
+
+    <refmiscinfo class="date">23 Mar 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>afp_signature.conf</refname>
+
+    <refpurpose>Configuration file used by afpd(8) to specify server
+        signature<indexterm>
+        <primary>afp_signature.conf</primary>
+      </indexterm></refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><filename>:STATEDIR:/netatalk/afp_signature.conf</filename> is the
+    configuration file used by <command>afpd</command> to specify
+    server signature automagically. The configuration lines are
+    composed like:</para>
+
+    <para><replaceable>"server name"</replaceable>
+    <replaceable>hexa-string</replaceable></para>
+
+    <para>The first field is server name. Server names must be quoted
+    if they contain spaces. The second field is the hexadecimal string
+    of 32 characters for 16-bytes server signature.</para>
+    <para>The leading spaces and tabs are ignored. Blank lines are ignored.
+    The lines prefixed with # are ignored. The illegal lines are ignored.
+    </para>
+
+    <note>
+        <para>Server Signature is unique 16-bytes identifier used to
+        prevent logging on to the same server twice. </para>
+        <para>Netatalk 2.0 and earlier generated server signature by using
+        gethostid(). There was a problem that another servers have the same
+        signature because the hostid is not unique enough.</para>
+        <para>Current netatalk generates the signature from random numbers and
+        saves it into afp_signature.conf. When starting next time, it
+        is read from this file. </para>
+        <para>This file should not be thoughtlessly edited and be copied
+        onto another server. If it wants to set the signature intentionally,
+        use the option "signature ="  in afp.conf. In this case,
+        afp_signature.conf is not used.</para>
+    </note>
+
+    <para></para>
+  </refsect1>
+
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>afp_signature.conf</title>
+
+      <programlisting># This is a comment.
+"My Server" 74A0BB94EC8C13988B2E75042347E528</programlisting>
+    </example>
+  </refsect1>
+
+  <refsect1>
+    <title>See also</title>
+
+    <para><citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>asip-status.pl</refentrytitle>
+
+        <manvolnum>1</manvolnum>
+      </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man5/afp_voluuid.conf.5.xml b/doc/manpages/man5/afp_voluuid.conf.5.xml
new file mode 100644 (file)
index 0000000..b91614e
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="afp_voluuid.conf.5">
+
+  <refmeta>
+    <refentrytitle>afp_voluuid.conf</refentrytitle>
+
+    <manvolnum>5</manvolnum>
+
+    <refmiscinfo class="date">23 Mar 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>afp_voluuid.conf</refname>
+
+    <refpurpose>Configuration file used by afpd(8) to specify UUID
+        for Time Machine volume<indexterm>
+        <primary>afp_voluuid.conf</primary>
+      </indexterm></refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><filename>:STATEDIR:/netatalk/afp_voluuid.conf</filename> is the
+    configuration file used by <command>afpd</command> to specify
+    UUID of Time Machine volume automagically. The configuration
+    lines are composed like:</para>
+
+    <para><replaceable>"volume name"</replaceable>
+    <replaceable>uuid-string</replaceable></para>
+
+    <para>The first field is volume name. Volume names must be quoted
+    if they contain spaces. The second field is the 36 character
+    hexadecimal ASCII string representation of a UUID.</para>
+    <para>The leading spaces and tabs are ignored. Blank lines are ignored.
+    The lines prefixed with # are ignored. The illegal lines are ignored.
+    </para>
+
+    <note>
+        <para>This UUID is advertised by Zeroconf in order to provide
+        robust disambiguation of Time Machine volume.</para>
+        <para>The afpd generates the UUID from random numbers and saves it
+        into afp_voluuid.conf, only when setting "time machine = yes" option
+        in afp.conf.</para>
+        <para>This file should not be thoughtlessly edited and be copied
+        onto another server.</para>
+    </note>
+
+    <para></para>
+  </refsect1>
+
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>afp_voluuid.conf three TM volumes on one netatalk</title>
+
+      <programlisting># This is a comment.
+"Backup for John Smith" 1573974F-0ABD-69CC-C40A-8519B681A0E1
+"bob" 39A487F4-55AA-8240-E584-69AA01800FE9
+mary 6331E2D1-446C-B68C-3066-D685AADBE911</programlisting>
+    </example>
+  </refsect1>
+
+  <refsect1>
+    <title>See also</title>
+
+    <para><citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>avahi-daemon</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>mDNSResponder</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man5/extmap.conf.5.xml b/doc/manpages/man5/extmap.conf.5.xml
new file mode 100644 (file)
index 0000000..f9802f3
--- /dev/null
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="extmap.conf.5">
+  <refmeta>
+    <refentrytitle>extmap.conf</refentrytitle>
+
+    <manvolnum>5</manvolnum>
+
+    <refmiscinfo class="date">19 Jan 2013</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>extmap.conf</refname>
+
+    <refpurpose>Configuration file used by afpd(8) to
+    specify file name extension mappings.<indexterm>
+        <primary>extmap.conf</primary>
+      </indexterm>
+      </refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv id="synopsis">
+    <cmdsynopsis>
+      <command>:ETCDIR:/extmap.conf<indexterm><primary>extmap.conf</primary></indexterm></command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>
+    <filename>:ETCDIR:/extmap.conf</filename> is the
+    configuration file used by <command>afpd</command> to
+    specify file name extension mappings.</para>
+
+    <para>The configuration lines are composed like:</para>
+
+    <para><filename>.extension</filename> <replaceable>[ type [
+    creator ] ]</replaceable></para>
+
+    <para>Any line beginning with a hash (“#”) character is ignored.
+    The leading-dot lines specify file name extension mappings.
+    The extension '.' sets the default creator and type for otherwise
+    untyped Unix files.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Extension is jpg. Type is "JPEG". Creator is "ogle".</title>
+
+            <programlisting>.jpg "JPEG" "ogle"</programlisting>
+          </example>
+
+    <example>
+      <title>Extension is lzh. Type is "LHA ". Creator is not defined.</title>
+
+            <programlisting>.lzh "LHA "</programlisting>
+          </example>
+
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para><citerefentry>
+        <refentrytitle>afp.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man8/afpd.8.xml b/doc/manpages/man8/afpd.8.xml
new file mode 100644 (file)
index 0000000..ee425fe
--- /dev/null
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="afpd.8">
+  <refmeta>
+    <refentrytitle>afpd</refentrytitle>
+
+    <manvolnum>8</manvolnum>
+
+    <refmiscinfo class="date">19 Jan 2013</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>afpd</refname>
+
+    <refpurpose>Apple Filing Protocol daemon</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>afpd<indexterm>
+          <primary>afpd</primary>
+        </indexterm></command>
+
+      <arg choice="opt">-d</arg>
+
+      <arg choice="opt">-F <replaceable>configfile</replaceable></arg>
+
+      <sbr />
+
+      <command>afpd<indexterm>
+          <primary>afpd</primary>
+        </indexterm></command>
+
+      <group choice="plain">
+        <arg choice="plain">-v</arg>
+        <arg choice="plain">-V</arg>
+        <arg choice="plain">-h</arg>
+      </group>
+
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><command>afpd</command> provides an Apple Filing Protocol (AFP)
+    interface to the Unix file system. It is normally started at boot time
+    by <command>netatalk</command>(8).</para>
+
+    <para><filename>:ETCDIR:/afp.conf</filename> is the configuration file
+    used by <command>afpd</command> to determine the behavior and
+    configuration of a file server.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+
+    <variablelist>
+      <varlistentry>
+        <term>-d</term>
+
+        <listitem>
+          <para>Specifies that the daemon should not fork.</para>
+        </listitem>
+      </varlistentry>
+
+
+      <varlistentry>
+        <term>-v</term>
+
+        <listitem>
+          <para>Print version information and exit.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-V</term>
+
+        <listitem>
+          <para>Print verbose information and exit.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-h</term>
+
+        <listitem>
+          <para>Print help and exit.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-F <replaceable>configfile</replaceable></term>
+
+        <listitem>
+          <para>Specifies the configuration file to use. (Defaults to
+          <filename>:ETCDIR:/afp.conf</filename>.)</para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SIGNALS</title>
+
+    <para>To shut down a user's <command>afpd</command> process it is
+      recommended that <command>SIGKILL (-9)</command>
+      <emphasis>NOT</emphasis> be used, except as a last resort, as this
+      may leave the CNID database in an inconsistent state. The safe way
+      to terminate an <command>afpd</command> is to send it a
+      <command>SIGTERM (-15)</command> signal and wait for it to die on
+      its own.</para>
+    <para>SIGTERM and SIGUSR1 signals that are sent to the main <command>afpd</command> process
+    are propagated to the children, so all will be affected.</para>
+
+    <variablelist>
+      <varlistentry>
+        <term>SIGTERM</term>
+        <listitem>
+          <para>Clean exit. Propagates from master to childs.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>SIGQUIT</term>
+        <listitem>
+          <para>Send this to the master <command>afpd</command>, it will
+          exit leaving all children running! Can be used to implement
+          AFP service without downtime.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>SIGHUP</term>
+        <listitem>
+          <para>Sending a <command>SIGHUP</command> to afpd will cause it to
+          reload its configuration files.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>SIGINT</term>
+        <listitem>
+          <para>Sending a <command>SIGINT</command> to a child
+          <command>afpd</command> enables <emphasis>max_debug</emphasis>
+          logging for this process. The log is sent to the file
+          <filename>/tmp/afpd.PID.XXXXXX</filename>. Sending another
+          <command>SIGINT</command> will revert to the original log settings.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>SIGUSR1</term>
+        <listitem>
+          <para>The <command>afpd</command> process will send the message "The
+          server is going down for maintenance." to the client and shut itself
+          down in 5 minutes. New connections are not allowed. If this is sent
+          to a child afpd, the other children are not affected. However, the
+          main process will still exit, disabling all new connections.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>SIGUSR2</term>
+        <listitem>
+          <para>The <command>afpd</command> process will look in the message
+          directory configured at build time for a file named message.pid. For
+          each one found, a the contents will be sent as a message to the
+          associated AFP client. The file is removed after the message is
+          sent. This should only be sent to a child
+          <command>afpd</command>.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>FILES</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><filename>:ETCDIR:/afp.conf</filename></term>
+
+        <listitem>
+          <para>configuration file used by afpd</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><filename>:STATEDIR:/netatalk/afp_signature.conf</filename></term>
+
+        <listitem>
+          <para>list of server signature</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><filename>:STATEDIR:/netatalk/afp_voluuid.conf</filename></term>
+
+        <listitem>
+          <para>list of UUID for Time Machine volume</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><filename>:ETCDIR:/extmap.conf</filename></term>
+
+        <listitem>
+          <para>file name extension mapping</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><filename>:ETCDIR:/msg/message.pid</filename></term>
+
+        <listitem>
+          <para>contains messages to be sent to users.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para><citerefentry>
+        <refentrytitle>netatalk</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>hosts_access</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp_signature.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp_voluuid.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>extmap.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>dbd</refentrytitle>
+
+        <manvolnum>1</manvolnum>
+      </citerefentry>.</para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man8/cnid_dbd.8.xml b/doc/manpages/man8/cnid_dbd.8.xml
new file mode 100644 (file)
index 0000000..89e8794
--- /dev/null
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="cnid_dbd.8">
+  <refmeta>
+    <refentrytitle>cnid_dbd</refentrytitle>
+
+    <manvolnum>8</manvolnum>
+
+    <refmiscinfo class="date">01 Jan 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>cnid_dbd</refname>
+
+    <refpurpose>implement access to CNID databases through a dedicated daemon
+    process</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>cnid_dbd<indexterm>
+          <primary>cnid_dbd</primary>
+        </indexterm><indexterm>
+          <primary>CNID backend</primary>
+        </indexterm><indexterm>
+          <primary>NFS</primary>
+
+          <secondary>Network File System</secondary>
+        </indexterm></command>
+
+      <sbr />
+
+      <command>cnid_dbd<indexterm>
+          <primary>cnid_dbd</primary>
+        </indexterm></command>
+
+        <group choice="plain">
+          <arg choice="plain">-v</arg>
+          <arg choice="plain">-V</arg>
+        </group>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para><command>cnid_dbd</command> provides an interface for storage and
+    retrieval of catalog node IDs (CNIDs) and related information to the
+    <emphasis remap="B">afpd</emphasis> daemon. CNIDs are a component of
+    Macintosh based file systems with semantics that map not easily onto Unix
+    file systems. This makes separate storage in a database necessary.
+    <command>cnid_dbd</command> is part of the <emphasis remap="B">CNID
+    backend</emphasis> framework of <emphasis remap="B">afpd</emphasis> and
+    implements the <emphasis remap="B">dbd</emphasis> backend.</para>
+
+    <para><command>cnid_dbd</command> is never started via the command line or
+    system startup scripts but only by the <emphasis
+    remap="B">cnid_metad</emphasis> daemon. There is one instance of
+    <command>cnid_dbd</command> per netatalk volume.</para>
+
+    <para><command>cnid_dbd</command> uses the <emphasis remap="B">Berkeley
+    DB</emphasis> database library and uses transactionally protected updates.
+    The <emphasis remap="B">dbd</emphasis> backend with transactions will
+    avoid corruption of the CNID database even if the system crashes
+    unexpectedly.</para>
+
+    <para><command>cnid_dbd</command> inherits the effective userid and
+    groupid from <emphasis remap="B">cnid_metad</emphasis> on startup, which
+    is normally caused by <emphasis remap="B">afpd</emphasis> serving a
+    netatalk volume to a client. It changes to the <emphasis
+    remap="B">Berkeley DB</emphasis> database home directory <emphasis
+    remap="I">dbdir</emphasis> that is associated with the volume. If the
+    userid inherited from <emphasis remap="B">cnid_metad</emphasis> is 0
+    (root), <command>cnid_dbd</command> will change userid and groupid to the
+    owner and group of the database home directory. Otherwise, it will
+    continue to use the inherited values. <command>cnid_dbd</command> will
+    then attempt to open the database and start serving requests using
+    filedescriptor <emphasis remap="I">clntfd</emphasis>. Subsequent instances
+    of <emphasis remap="B">afpd</emphasis> that want to access the same volume
+    are redirected to the running <command>cnid_dbd</command> process by
+    <emphasis remap="B">cnid_metad</emphasis> via the filedescriptor <emphasis
+    remap="I">ctrlfd</emphasis>.</para>
+
+    <para><command>cnid_dbd</command> can be configured to run forever or to
+    exit after a period of inactivity. If <command>cnid_dbd</command> receives
+    a TERM or an INT signal it will exit cleanly after flushing dirty database
+    buffers to disk and closing <emphasis remap="B">Berkeley DB</emphasis>
+    database environments. It is safe to terminate <command>cnid_dbd</command>
+    this way, it will be restarted when necessary. Other signals are not
+    handled and will cause an immediate exit, possibly leaving the CNID
+    database in an inconsistent state (no transactions) or losing recent
+    updates during recovery (transactions).</para>
+
+    <para>The <emphasis remap="B">Berkeley DB</emphasis> database subsystem
+    will create files named log.xxxxxxxxxx in the database home directory
+    <emphasis remap="I">dbdir</emphasis>, where xxxxxxxxxx is a monotonically
+    increasing integer. These files contain the transactional database
+    changes. They will be removed regularly, unless the <emphasis
+    remap="B">logfile_autoremove</emphasis> option is specified in the
+    <emphasis remap="I">db_param</emphasis> configuration file (see
+    below) with a value of 0 (default 1).</para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><option>-v, -V</option></term>
+       
+        <listitem>
+          <para>Show version and exit.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>CONFIGURATION</title>
+
+    <para><command>cnid_dbd</command> reads configuration information from the
+    file <emphasis remap="I">db_param</emphasis> in the database directory
+    <emphasis remap="I">dbdir</emphasis> on startup. If the file does not
+    exist or a parameter is not listed, suitable default values are used. The
+    format for a single parameter is the parameter name, followed by one or
+    more spaces, followed by the parameter value, followed by a newline. The
+    following parameters are currently recognized:</para>
+
+    <variablelist remap="TP">
+      <varlistentry>
+        <term><emphasis remap="B">logfile_autoremove</emphasis></term>
+
+        <listitem>
+          <para>If set to 0, unused Berkeley DB transactional logfiles
+          (log.xxxxxxxxxx in the database home directory) are not removed on
+          startup of <command>cnid_dbd</command> and on a regular basis.
+          Default: 1.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><emphasis remap="B">cachesize</emphasis></term>
+
+        <listitem>
+          <para>Determines the size of the Berkeley DB cache in kilobytes.
+          Default: 8192. Each <command>cnid_dbd</command> process grabs that
+          much memory on top of its normal memory footprint. It can be used to
+          tune database performance. The <emphasis
+          remap="B">db_stat</emphasis> utility with the <option>-m</option>
+          option that comes with Berkley DB can help you determine ether you
+          need to change this value. The default is pretty conservative so
+          that a large percentage of requests should be satisfied from the
+          cache directly. If memory is not a bottleneck on your system you
+          might want to leave it at that value. The <emphasis
+          remap="B">Berkeley DB Tutorial and Reference Guide</emphasis> has a
+          section <emphasis remap="B">Selecting a cache size</emphasis> that
+          gives more detailed information.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><emphasis remap="B">flush_frequency</emphasis></term>
+
+        <term><emphasis remap="B">flush_interval</emphasis></term>
+
+        <listitem>
+          <para><emphasis remap="I">flush_frequency</emphasis> (Default: 1000)
+          and <emphasis remap="I">flush_interval</emphasis> (Default: 1800)
+          control how often changes to the database are checkpointed. Both of
+          these operations are performed if either i) more than <emphasis
+          remap="I">flush_frequency</emphasis> requests have been received or
+          ii) more than <emphasis remap="I">flush_interval</emphasis> seconds
+          have elapsed since the last save/checkpoint. Be careful to check
+          your harddisk configuration for on disk cache settings. Many IDE
+          disks just cache writes as the default behaviour, so even flushing
+          database files to disk will not have the desired effect.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><emphasis remap="B">fd_table_size</emphasis></term>
+
+        <listitem>
+          <para>is the maximum number of connections (filedescriptors) that
+          can be open for <emphasis remap="B">afpd</emphasis> client processes
+          in <emphasis remap="B">cnid_dbd.</emphasis> Default: 512. If this
+          number is exceeded, one of the existing connections is closed and
+          reused. The affected <emphasis remap="B">afpd</emphasis> process
+          will transparently reconnect later, which causes slight overhead. On
+          the other hand, setting this parameter too high could affect
+          performance in <command>cnid_dbd</command> since all descriptors
+          have to be checked in a <function>select()</function> system call,
+          or worse, you might exceed the per process limit of open file
+          descriptors on your system. It is safe to set the value to 1 on
+          volumes where only one <emphasis remap="B">afpd</emphasis> client
+          process is expected to run, e.g. home directories.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><emphasis remap="B">idle_timeout</emphasis></term>
+
+        <listitem>
+          <para>is the number of seconds of inactivity before an idle
+          <command>cnid_dbd</command> exits. Default: 600. Set this to 0 to
+          disable the timeout.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>UPDATING</title>
+
+    <para>Note that the first version to appear <emphasis>after</emphasis>
+    Netatalk 2.1 ie Netatalk 2.1.1, will support BerkeleyDB updates on the fly
+    without manual intervention. In other words Netatalk 2.1 does contain code
+    to prepare the BerkeleyDB database for upgrades and to upgrade it in case
+    it has been prepared before. That means it can't upgrade a 2.0.x version
+    because that one didn't prepare the database.</para>
+
+    <para>In order to update between older Netatalk releases using different
+    BerkeleyDB library versions, follow this steps:</para>
+
+    <itemizedlist>
+      <listitem>
+        <para>Stop the to be upgraded old version of Netatalk</para>
+      </listitem>
+
+      <listitem>
+        <para>Using the old BerkeleyDB utilities run <command>db_recover -h
+        &lt;path to .AppleDB&gt;</command></para>
+      </listitem>
+
+      <listitem>
+        <para>Using the new BerkeleyDB utilities run <command>db_upgrade -v -h
+        &lt;path to .AppleDB&gt; -f cnid2.db</command></para>
+      </listitem>
+
+      <listitem>
+        <para>Again using the new BerkeleyDB utilities run
+        <command>db_checkpoint -1 -h &lt;path to .AppleDB&gt;</command></para>
+      </listitem>
+
+      <listitem>
+        <para>Start the the new version of Netatalk</para>
+      </listitem>
+    </itemizedlist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para><citerefentry>
+        <refentrytitle>cnid_metad</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>dbd</refentrytitle>
+
+        <manvolnum>1</manvolnum>
+      </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man8/cnid_metad.8.xml b/doc/manpages/man8/cnid_metad.8.xml
new file mode 100644 (file)
index 0000000..587694b
--- /dev/null
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="cnid_metad.8">
+  <refmeta>
+    <refentrytitle>cnid_metad</refentrytitle>
+
+    <manvolnum>8</manvolnum>
+
+    <refmiscinfo class="date">23 Mar 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>cnid_metad</refname>
+
+    <refpurpose>start cnid_dbd daemons on request</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>cnid_metad<indexterm>
+          <primary>cnid_metad</primary>
+        </indexterm></command>
+
+      <arg choice="opt">-d</arg>
+
+      <arg choice="opt"><arg choice="plain">-F </arg><arg
+      choice="plain"><replaceable>configuration file</replaceable></arg></arg>
+
+      <sbr />
+
+      <command>cnid_metad<indexterm>
+          <primary>cnid_metad</primary>
+        </indexterm></command>
+
+       <group choice="plain">
+         <arg choice="plain">-v</arg>
+         <arg choice="plain">-V</arg>
+       </group>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para><command>cnid_metad</command> waits for requests from <emphasis
+    remap="B">afpd</emphasis> to start up instances of the <emphasis
+    remap="B">cnid_dbd</emphasis> daemon. It keeps track of the status of a
+    <emphasis remap="B">cnid_dbd</emphasis> instance once started and will
+    restart it if necessary. <command>cnid_metad</command> is normally started
+    at boot time by <command>netatalk</command>(8) and runs
+    until shutdown.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist remap="TP">
+     <varlistentry>
+        <term><option>-d</option></term>
+
+        <listitem>
+          <para><emphasis remap="B">cnid_metad will remain in the foreground
+          and</emphasis> will also leave the standard input, standard output
+          and standard error file descriptors open. Useful for
+          debugging.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-F</option> <replaceable>configuration file</replaceable></term>
+
+        <listitem>
+          <para>Use <emphasis remap="I">configuration file</emphasis> as the
+            configuration file. The default is
+            <emphasis remap="I">:ETCDIR:/afp.conf</emphasis>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-v, -V</option></term>
+
+        <listitem>
+          <para>Show version and exit.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>CAVEATS</title>
+
+    <para><command>cnid_metad</command> does not block or catch any signals
+    apart from SIGPIPE. It will therefore exit on most signals received. This
+    will also cause all instances of <emphasis remap="B">cnid_dbd's</emphasis>
+    started by that <command>cnid_metad</command> to exit gracefully. Since
+    state about and IPC access to the subprocesses is only maintained in
+    memory by <command>cnid_metad</command> this is desired behaviour. As soon
+    as <command>cnid_metad</command> is restarted <emphasis
+    remap="B">afpd</emphasis> processes will transparently reconnect.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para><citerefentry>
+        <refentrytitle>netatalk</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>cnid_dbd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>dbd</refentrytitle>
+
+        <manvolnum>1</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry></para>
+  </refsect1>
+</refentry>
diff --git a/doc/manpages/man8/netatalk.8.xml b/doc/manpages/man8/netatalk.8.xml
new file mode 100644 (file)
index 0000000..e9496da
--- /dev/null
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<refentry id="netatalk.8">
+  <refmeta>
+    <refentrytitle>netatalk</refentrytitle>
+
+    <manvolnum>8</manvolnum>
+
+    <refmiscinfo class="date">22 Mar 2012</refmiscinfo>
+
+    <refmiscinfo class="source">:NETATALK_VERSION:</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>netatalk</refname>
+
+    <refpurpose>Netatalk AFP server service controller daemon</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>netatalk<indexterm>
+          <primary>netatalk</primary>
+        </indexterm></command>
+
+      <sbr />
+
+      <command>netatalk<indexterm>
+          <primary>netatalk</primary>
+        </indexterm></command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><command>netatalk</command> is the service controller daemon
+    responsible for starting and restarting the AFP daemon
+    <command>afpd</command> and the CNID daemon <command>cnid_metad</command>.
+    It is normally started at boot time from /etc/rc.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>SIGNALS</title>
+
+    <variablelist>
+      <varlistentry>
+        <term>SIGTERM</term>
+
+        <listitem>
+          <para>Stop Netatalk service, AFP and CNID daemons</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>SIGHUP</term>
+
+        <listitem>
+          <para>Sending a <command>SIGHUP</command> will cause the AFP daemon
+          reload its configuration file.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>FILES</title>
+
+    <variablelist>
+      <varlistentry>
+        <term><filename>:ETCDIR:/afp.conf</filename></term>
+
+        <listitem>
+          <para>configuration file used by afpd and cnid_metad</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+
+    <para><citerefentry>
+        <refentrytitle>afpd</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>cnid_metad</refentrytitle>
+
+        <manvolnum>8</manvolnum>
+      </citerefentry>, <citerefentry>
+        <refentrytitle>afp.conf</refentrytitle>
+
+        <manvolnum>5</manvolnum>
+      </citerefentry>.</para>
+  </refsect1>
+</refentry>
diff --git a/doc/manual/configuration.xml b/doc/manual/configuration.xml
new file mode 100644 (file)
index 0000000..3bf6e0f
--- /dev/null
@@ -0,0 +1,1554 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="configuration">
+  <title>Setting up Netatalk</title>
+
+  <sect1>
+    <title>File Services<indexterm>
+        <primary>File Services</primary>
+
+        <secondary>Netatalk's File Services</secondary>
+      </indexterm></title>
+
+    <para>Netatalk supplies AFP<indexterm>
+        <primary>AFP</primary>
+
+        <secondary>Apple Filing Protocol</secondary>
+      </indexterm> services.</para>
+
+    <sect2>
+      <title>Setting up the AFP file server</title>
+
+      <para>AFP (the Apple Filing Protocol) is the protocol Apple Macintoshes
+      use for file services. The protocol has evolved over the years. The
+      latest changes to the protocol, called "AFP 3.3", were added with the
+      release of Snow Leopard<indexterm>
+          <primary>Snow Leopard</primary>
+
+          <secondary>Mac OS X 10.6</secondary>
+        </indexterm> (Mac OS X 10.6).</para>
+
+      <para>The afpd daemon offers the fileservices to Apple clients. The only
+      configuration file is <filename>afp.conf</filename>. It uses a ini style
+      configuration syntax.</para>
+
+      <para>Mac OS X 10.5 (Leopard) added support for Time Machine backups
+      over AFP. Two new functions ensure that backups are written to spinning
+      disk, not just in the server's cache. Different host operating systems
+      honour this cache flushing differently. To make a volume a Time Machine
+      target use the volume option "<option>time machine =
+      yes</option>".</para>
+
+      <para>Starting with Netatalk 2.1 UNIX symlinks<indexterm>
+          <primary>symlink</primary>
+
+          <secondary>UNIX symlink</secondary>
+        </indexterm> can be used on the server. Semantics are the same as for
+      eg NFS, ie they are not resolved on the server side but instead it's
+      completely up to the client to resolve them, resulting in links that
+      point somewhere inside the clients filesystem view.</para>
+
+      <sect3>
+        <title>afp.conf</title>
+
+        <para><filename>afp.conf</filename> is the configuration file used by
+        afpd to determine the behaviour and configuration of the AFP file
+        serverand the AFP volume that it provides.</para>
+
+        <para>The <filename>afp.conf</filename> is divided into several
+        sections:<variablelist>
+            <varlistentry>
+              <term>[Global]</term>
+
+              <listitem>
+                <para>The global section defines general server options</para>
+              </listitem>
+            </varlistentry>
+
+            <varlistentry>
+              <term>[Homes]</term>
+
+              <listitem>
+                <para>The homes section defines user home volumes</para>
+              </listitem>
+            </varlistentry>
+          </variablelist>Any section not called <option>Global</option> or
+        <option>Homes</option> is interpreted as an AFP volume.</para>
+
+        <para>For sharing user homes by defining a <option>Homes</option>
+        section you must specify the option <option>basedir regex</option>
+        which can be a simple string with the path to the parent directory of
+        all user homes or a regular expression.</para>
+
+        <para>Example:</para>
+
+        <para><programlisting>[Homes]
+basedir regex = /home
+</programlisting></para>
+
+        <para>Now any user logging into the AFP server will have a user volume
+        available whos path is <filename>/home/NAME</filename>.</para>
+
+        <para>A more complex setup would be a server with a large amount of
+        user homes which are split across eg two different
+        filesystems:<itemizedlist>
+            <listitem>
+              <para>/RAID1/homes</para>
+            </listitem>
+
+            <listitem>
+              <para>/RAID2/morehomes</para>
+            </listitem>
+          </itemizedlist>The following configuration is
+        required:<programlisting>[Homes]
+basedir regex = /RAID./.*homes
+</programlisting></para>
+
+        <para>If <option>basedir regex</option> contains symlink, set the
+        canonicalized absolute path. When <filename>/home</filename> links to
+        <filename>/usr/home</filename>: <programlisting>[Homes]
+basedir regex = /usr/home</programlisting></para>
+
+        <para>For a more detailed explanation of the available options, please
+        refer to the <citerefentry>
+            <refentrytitle>afp.conf</refentrytitle>
+
+            <manvolnum>5</manvolnum>
+          </citerefentry> man page.</para>
+      </sect3>
+    </sect2>
+
+    <sect2 id="CNID-backends">
+      <title>CNID<indexterm>
+          <primary>CNID</primary>
+
+          <secondary>Catalog Node ID</secondary>
+        </indexterm> backends<indexterm>
+          <primary>Backend</primary>
+
+          <secondary>CNID backend</secondary>
+        </indexterm></title>
+
+      <para>Unlike other protocols like SMB or NFS, the AFP protocol mostly
+      refers to files and directories by ID and not by a path (the IDs are
+      also called CNID, that means Catalog Node ID). A typical AFP request
+      uses a directory ID<indexterm>
+          <primary>DID</primary>
+
+          <secondary>Directory ID</secondary>
+        </indexterm> and a filename, something like <phrase>"server, please
+      open the file named 'Test' in the directory with id 167"</phrase>. For
+      example "Aliases" on the Mac basically work by ID (with a fallback to
+      the absolute path in more recent AFP clients. But this applies only to
+      Finder, not to applications).</para>
+
+      <para>Every file in an AFP volume has to have a unique file ID<indexterm>
+          <primary>FID</primary>
+
+          <secondary>File ID</secondary>
+        </indexterm>, IDs must, according to the specs, never be reused, and
+      IDs are 32 bit numbers (Directory IDs use the same ID pool). So, after
+      ~4 billion files/folders have been written to an AFP volume, the ID pool
+      is depleted and no new file can be written to the volume. No whining
+      please :-)</para>
+
+      <para>Netatalk needs to map IDs to files and folders in the host
+      filesystem. To achieve this, several different CNID backends<indexterm>
+          <primary>CNID backend</primary>
+        </indexterm> are available and can be choosed by the <option>cnid
+      scheme</option><indexterm>
+          <primary>cnidscheme</primary>
+
+          <secondary>specifying a CNID backend</secondary>
+        </indexterm> option in the <citerefentry>
+          <refentrytitle>afp.conf</refentrytitle>
+
+          <manvolnum>5</manvolnum>
+        </citerefentry> configuration file. A CNID backend is basically a
+      database storing ID &lt;-&gt; name mappings.</para>
+
+      <para>The CNID Databases are by default located in
+      <filename>/var/netatalk/CNID</filename>.</para>
+
+      <para>There is a command line utility called <command>dbd</command>
+      available which can be used to verify, repair and rebuild the CNID
+      database.</para>
+
+      <note>
+        <para>There are some CNID related things you should keep in mind when
+        working with netatalk:</para>
+
+        <itemizedlist>
+          <listitem>
+            <para>Don't nest volumes<indexterm>
+                <primary>Nested volumes</primary>
+              </indexterm>.</para>
+          </listitem>
+
+          <listitem>
+            <para>CNID backends are databases, so they turn afpd into a file
+            server/database mix.</para>
+          </listitem>
+
+          <listitem>
+            <para>If there's no more space on the filesystem left, the
+            database will get corrupted. You can work around this by either
+            using the <option>vol dbpath</option> option and put the database
+            files into another location or, if you use quotas, make sure the
+            CNID database folder is owned by a user/group without a
+            quota<indexterm>
+                <primary>Quotas</primary>
+
+                <secondary>Disk usage quotas</secondary>
+              </indexterm>.</para>
+          </listitem>
+
+          <listitem>
+            <para>Be careful with CNID databases for volumes that are mounted
+            via NFS. That is a pretty audacious decision to make anyway, but
+            putting a database there as well is really asking for trouble,
+            i.e. database corruption. Use the <option>vol dbpath</option>
+            directive to put the databases onto a local disk if you must use
+            NFS<indexterm>
+                <primary>NFS</primary>
+
+                <secondary>Network File System</secondary>
+              </indexterm> mounted volumes.</para>
+          </listitem>
+        </itemizedlist>
+      </note>
+
+      <sect3>
+        <title>cdb<indexterm>
+            <primary>CDB</primary>
+
+            <secondary>"cdb" CNID backend</secondary>
+          </indexterm></title>
+
+        <para>The "concurrent database" backend is based on Berkeley DB. With
+        this backend, several afpd daemons access the CNID database directly.
+        Berkeley DB locking is used to synchronize access, if more than one
+        afpd process is active for a volume. The drawback is, that the crash
+        of a single afpd process might corrupt the database. cdb should only
+        be used when sharing home directories for a larger number of users
+        <emphasis>and</emphasis> it has been determined that a large number of
+        <command>cnid_dbd</command> processes is problematic.</para>
+      </sect3>
+
+      <sect3>
+        <title>dbd<indexterm>
+            <primary>DBD</primary>
+
+            <secondary>"dbd" CNID backend</secondary>
+          </indexterm></title>
+
+        <para>Access to the CNID database is restricted to the cnid_dbd daemon
+        process. afpd processes communicate with the daemon for database reads
+        and updates. The probability for database corruption is practically
+        zero.</para>
+
+        <para>This is the default backend since Netatalk 2.1.</para>
+      </sect3>
+
+      <sect3>
+        <title>tdb<indexterm>
+            <primary>tdb</primary>
+
+            <secondary>"tdb" CNID backend</secondary>
+          </indexterm></title>
+
+        <para><abbrev>tdb</abbrev> is another persistent CNID database, it's
+        Samba's <emphasis>Trivial Database</emphasis>. It could be used
+        instead of <abbrev>cdb</abbrev> for user volumes.<important>
+            <para>Only ever use it for volumes that are
+            <emphasis>not</emphasis> shared and accessed by multiple clients
+            at once !</para>
+          </important>This backend is also used internally (as in-memory CNID
+        database) as a fallback in case opening the primary database can't be
+        opened, because <abbrev>tdb</abbrev> can work as in-memory database.
+        This of course means upon restart the CNIDs are gone.</para>
+      </sect3>
+
+      <sect3>
+        <title>last<indexterm>
+            <primary>Last</primary>
+
+            <secondary>"last" CNID backend</secondary>
+          </indexterm></title>
+
+        <para>The last backend is a in-memory tdb database. It is not
+        persistent. Starting with netatalk 3.0, it becomes the <emphasis> read
+        only mode</emphasis> automatically. This is useful e.g. for
+        CD-ROMs.</para>
+      </sect3>
+    </sect2>
+
+    <sect2 id="charsets">
+      <title>Charsets<indexterm>
+          <primary>Charset</primary>
+
+          <secondary>character set</secondary>
+        </indexterm>/Unicode<indexterm>
+          <primary>Unicode</primary>
+        </indexterm></title>
+
+      <para></para>
+
+      <sect3>
+        <title>Why Unicode?</title>
+
+        <para>Internally, computers don't know anything about characters and
+        texts, they only know numbers. Therefore, each letter is assigned a
+        number. A character set, often referred to as
+        <emphasis>charset</emphasis> or
+        <emphasis>codepage</emphasis><indexterm>
+            <primary>Codepage</primary>
+          </indexterm>, defines the mappings between numbers and
+        letters.</para>
+
+        <para>If two or more computer systems need to communicate with each
+        other, the have to use the same character set. In the 1960s the
+        ASCII<indexterm>
+            <primary>ASCII</primary>
+
+            <secondary>American Standard Code for Information
+            Interchange</secondary>
+          </indexterm> (American Standard Code for Information Interchange)
+        character set was defined by the American Standards Association. The
+        original form of ASCII represented 128 characters, more than enough to
+        cover the English alphabet and numerals. Up to date, ASCII has been
+        the normative character scheme used by computers.</para>
+
+        <para>Later versions defined 256 characters to produce a more
+        international fluency and to include some slightly esoteric graphical
+        characters. Using this mode of encoding each character takes exactly
+        one byte. Obviously, 256 characters still wasn't enough to map all the
+        characters used in the various languages into one character
+        set.</para>
+
+        <para>As a result localized character sets were defined later, e.g the
+        ISO-8859 character sets. Most operating system vendors introduced
+        their own characters sets to satisfy their needs, e.g. IBM defined the
+        <emphasis>codepage 437 (DOSLatinUS)</emphasis>, Apple introduced the
+        <emphasis>MacRoman</emphasis><indexterm>
+            <primary>MacRoman</primary>
+
+            <secondary>MacRoman charset</secondary>
+          </indexterm> codepage and so on. The characters that were assigned
+        number larger than 127 were referred to as
+        <emphasis>extended</emphasis> characters. These character sets
+        conflict with another, as they use the same number for different
+        characters, or vice versa.</para>
+
+        <para>Almost all of those characters sets defined 256 characters,
+        where the first 128 (0-127) character mappings are identical to ASCII.
+        As a result, communication between systems using different codepages
+        was effectively limited to the ASCII charset.</para>
+
+        <para>To solve this problem new, larger character sets were defined.
+        To make room for more character mappings, these character sets use at
+        least 2 bytes to store a character. They are therefore referred to as
+        <emphasis>multibyte</emphasis> character sets.</para>
+
+        <para>One standardized multibyte charset encoding scheme is known as
+        <ulink url="http://www.unicode.org/">unicode</ulink>. A big advantage
+        of using a multibyte charset is that you only need one. There is no
+        need to make sure two computers use the same charset when they are
+        communicating.</para>
+      </sect3>
+
+      <sect3>
+        <title>character sets used by Apple</title>
+
+        <para>In the past, Apple clients used single-byte charsets to
+        communicate over the network. Over the years Apple defined a number of
+        codepages, western users will most likely be using the
+        <emphasis>MacRoman</emphasis> codepage.</para>
+
+        <para>Codepages defined by Apple include:</para>
+
+        <itemizedlist>
+          <listitem>
+            <para>MacArabic, MacFarsi</para>
+          </listitem>
+
+          <listitem>
+            <para>MacCentralEurope</para>
+          </listitem>
+
+          <listitem>
+            <para>MacChineseSimple</para>
+          </listitem>
+
+          <listitem>
+            <para>MacChineseTraditional</para>
+          </listitem>
+
+          <listitem>
+            <para>MacCroation</para>
+          </listitem>
+
+          <listitem>
+            <para>MacCyrillic</para>
+          </listitem>
+
+          <listitem>
+            <para>MacDevanagari</para>
+          </listitem>
+
+          <listitem>
+            <para>MacGreek</para>
+          </listitem>
+
+          <listitem>
+            <para>MacHebrew</para>
+          </listitem>
+
+          <listitem>
+            <para>MacIcelandic</para>
+          </listitem>
+
+          <listitem>
+            <para>MacJapanese</para>
+          </listitem>
+
+          <listitem>
+            <para>MacKorean</para>
+          </listitem>
+
+          <listitem>
+            <para>MacRoman</para>
+          </listitem>
+
+          <listitem>
+            <para>MacRomanian</para>
+          </listitem>
+
+          <listitem>
+            <para>MacThai</para>
+          </listitem>
+
+          <listitem>
+            <para>MacTurkish</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>Starting with Mac OS X and AFP3, <ulink
+        url="http://www.utf-8.com/">UTF-8</ulink> is used. UTF-8 encodes
+        Unicode characters in an ASCII compatible way, each Unicode character
+        is encoded into 1-6 ASCII characters. UTF-8 is therefore not really a
+        charset itself, it's an encoding of the Unicode charset.</para>
+
+        <para>To complicate things, Unicode defines several <emphasis> <ulink
+        url="http://www.unicode.org/reports/tr15/index.html">normalization</ulink>
+        </emphasis> forms. While <ulink
+        url="http://www.samba.org">samba</ulink><indexterm>
+            <primary>Samba</primary>
+          </indexterm> uses <emphasis>precomposed</emphasis><indexterm>
+            <primary>Precomposed</primary>
+
+            <secondary>Precomposed Unicode normalization</secondary>
+          </indexterm> Unicode, which most Unix tools prefer as well, Apple
+        decided to use the <emphasis>decomposed</emphasis><indexterm>
+            <primary>Decomposed</primary>
+
+            <secondary>Decomposed Unicode normalization</secondary>
+          </indexterm> normalization.</para>
+
+        <para>For example lets take the German character
+        '<keycode>ä</keycode>'. Using the precomposed normalization, Unicode
+        maps this character to 0xE4. In decomposed normalization, 'ä' is
+        actually mapped to two characters, 0x61 and 0x308. 0x61 is the mapping
+        for an 'a', 0x308 is the mapping for a <emphasis>COMBINING
+        DIAERESIS</emphasis>.</para>
+
+        <para>Netatalk refers to precomposed UTF-8 as
+        <emphasis>UTF8</emphasis><indexterm>
+            <primary>UTF8</primary>
+
+            <secondary>Netatalk's precomposed UTF-8 encoding</secondary>
+          </indexterm> and to decomposed UTF-8 as
+        <emphasis>UTF8-MAC</emphasis><indexterm>
+            <primary>UTF8-MAC</primary>
+
+            <secondary>Netatalk's decomposed UTF-8 encoding</secondary>
+          </indexterm>.</para>
+      </sect3>
+
+      <sect3>
+        <title>afpd and character sets</title>
+
+        <para>To support new AFP 3.x and older AFP 2.x clients at the same
+        time, afpd needs to be able to convert between the various charsets
+        used. AFP 3.x clients always use UTF8-MAC, AFP 2.x clients use one of
+        the Apple codepages.</para>
+
+        <para>At the time of this writing, netatalk supports the following
+        Apple codepages:</para>
+
+        <itemizedlist>
+          <listitem>
+            <para>MAC_CENTRALEUROPE</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_CHINESE_SIMP</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_CHINESE_TRAD</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_CYRILLIC</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_GREEK</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_HEBREW</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_JAPANESE</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_KOREAN</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_ROMAN</para>
+          </listitem>
+
+          <listitem>
+            <para>MAC_TURKISH</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>afpd handles three different character set options:</para>
+
+        <variablelist>
+          <varlistentry>
+            <term>unix charset<indexterm>
+                <primary>unix charset</primary>
+
+                <secondary>afpd's unix charset setting</secondary>
+              </indexterm></term>
+
+            <listitem>
+              <para>This is the codepage used internally by your operating
+              system. If not specified, it defaults to <option>UTF8</option>.
+              If <option>LOCALE</option> is specified and your system support
+              Unix locales, afpd tries to detect the codepage. afpd uses this
+              codepage to read its configuration files, so you can use
+              extended characters for volume names, login messages, etc. see
+              <citerefentry>
+                  <refentrytitle>afp.conf</refentrytitle>
+
+                  <manvolnum>5</manvolnum>
+                </citerefentry>.</para>
+            </listitem>
+          </varlistentry>
+
+          <varlistentry>
+            <term>mac charset<indexterm>
+                <primary>mac charset</primary>
+
+                <secondary>afpd's mac charset setting</secondary>
+              </indexterm></term>
+
+            <listitem>
+              <para>As already mentioned, older Mac OS clients (up to AFP 2.2)
+              use codepages to communicate with afpd. However, there is no
+              support for negotiating the codepage used by the client in the
+              AFP protocol. If not specified otherwise, afpd assumes the
+              <emphasis>MacRoman</emphasis> codepage is used. In case you're
+              clients use another codepage, e.g.
+              <emphasis>MacCyrillic</emphasis>, you'll <emphasis
+              role="bold">have</emphasis> to explicitly configure this. see
+              <citerefentry>
+                  <refentrytitle>afp.conf</refentrytitle>
+
+                  <manvolnum>5</manvolnum>
+                </citerefentry>.</para>
+            </listitem>
+          </varlistentry>
+
+          <varlistentry>
+            <term>vol charset<indexterm>
+                <primary>vol charset</primary>
+
+                <secondary>afpd's vol charset setting</secondary>
+              </indexterm></term>
+
+            <listitem>
+              <para>This defines the charset afpd should use for filenames on
+              disk. By default, it is the same as <option>unix
+              charset</option>. If you have <ulink
+              url="http://www.gnu.org/software/libiconv/">iconv</ulink><indexterm>
+                  <primary>Iconv</primary>
+
+                  <secondary>iconv encoding conversion engine</secondary>
+                </indexterm> installed, you can use any iconv provided charset
+              as well.</para>
+
+              <para>afpd needs a way to preserve extended macintosh
+              characters, or characters illegal in unix filenames, when saving
+              files on a unix filesystem. Earlier versions used the the so
+              called CAP encoding<indexterm>
+                  <primary>CAP encoding</primary>
+
+                  <secondary>CAP style character encoding</secondary>
+                </indexterm>. An extended character (&gt;0x7F) would be
+              converted to a :xx hex sequence, e.g. the Apple Logo (MacRoman:
+              0xF0) was saved as :f0. Some special characters will be
+              converted as to :xx notation as well. '/' will be encoded to
+              :2f, if <option>usedots</option> was not specified, a leading
+              dot '.' will be encoded as :2e.</para>
+
+              <para>Even though this version now uses <option>UTF8</option> as
+              the default encoding for filenames, '/' will be converted to
+              ':'. For western users another useful setting could be
+              <option>vol charset = ISO-8859-15</option>.</para>
+
+              <para>If a character cannot be converted from the <option>mac
+              charset</option> to the selected <option>vol charset</option>,
+              afpd will save it as a CAP encoded character. For AFP3 clients,
+              afpd will convert the UTF8 character to <option>mac
+              charset</option> first. If this conversion fails, you'll receive
+              a -50 error on the mac. <emphasis>Note</emphasis>: Whenever you
+              can, please stick with the default UTF8 volume format. see
+              <citerefentry>
+                  <refentrytitle>afp.conf</refentrytitle>
+
+                  <manvolnum>5</manvolnum>
+                </citerefentry>.</para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+      </sect3>
+    </sect2>
+
+    <sect2 id="authentication">
+      <title>Authentication<indexterm>
+          <primary>Authentication</primary>
+
+          <secondary>between AFP client and server</secondary>
+        </indexterm></title>
+
+      <sect3>
+        <title>AFP authentication basics</title>
+
+        <para>Apple chose a flexible model called "User Authentication
+        Modules"<indexterm>
+            <primary>UAM</primary>
+
+            <secondary>User Authentication Module</secondary>
+          </indexterm> (UAMs) for authentication purposes between AFP client
+        and server. An AFP client initially connecting to an AFP server will
+        ask for the list of UAMs which the server provides, and will choose
+        the one with strongest encryption that the client supports.</para>
+
+        <para>Several UAMs have been developed by Apple over the time, some by
+        3rd-party developers.</para>
+      </sect3>
+
+      <sect3>
+        <title>UAMs supported by Netatalk</title>
+
+        <para>Netatalk supports the following ones by default:</para>
+
+        <itemizedlist>
+          <listitem>
+            <para>"No User Authent"<indexterm>
+                <primary>No User Authent</primary>
+
+                <secondary>"No User Authent" UAM (guest access)</secondary>
+              </indexterm> UAM (guest access without authentication)</para>
+          </listitem>
+
+          <listitem>
+            <para>"Cleartxt Passwrd"<indexterm>
+                <primary>Cleartxt Passwrd</primary>
+
+                <secondary>"Cleartxt Passwrd" UAM</secondary>
+              </indexterm> UAM (no password encryption)</para>
+          </listitem>
+
+          <listitem>
+            <para>"Randnum exchange"<indexterm>
+                <primary>Randnum exchange</primary>
+
+                <secondary>"Randnum exchange" UAM</secondary>
+              </indexterm>/"2-Way Randnum exchange"<indexterm>
+                <primary>2-Way Randnum exchange</primary>
+
+                <secondary>"2-Way Randnum exchange" UAM</secondary>
+              </indexterm> UAMs (weak password encryption, separate password
+            storage)</para>
+          </listitem>
+
+          <listitem>
+            <para>"DHCAST128"<indexterm>
+                <primary>DHCAST128</primary>
+
+                <secondary>"DHCAST128" UAM</secondary>
+              </indexterm> UAM (stronger password encryption)</para>
+          </listitem>
+
+          <listitem>
+            <para>"DHX2"<indexterm>
+                <primary>DHX2</primary>
+
+                <secondary>"DHX2" UAM</secondary>
+              </indexterm> UAM (successor of DHCAST128)</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>There exist other optional UAMs as well:</para>
+
+        <itemizedlist>
+          <listitem>
+            <para>"PGPuam 1.0"<indexterm>
+                <primary>PGPuam 1.0</primary>
+
+                <secondary>"PGPuam 1.0" UAM</secondary>
+              </indexterm><indexterm>
+                <primary>uams_pgp.so</primary>
+
+                <secondary>"PGPuam 1.0" UAM</secondary>
+              </indexterm> UAM (PGP-based authentication for pre-Mac OS X
+            clients. You'll also need the <ulink
+            url="http://www.vmeng.com/vinnie/papers/pgpuam.html">PGPuam
+            client</ulink> to let this work)</para>
+
+            <para>You'll have to add <filename>"--enable-pgp-uam"</filename>
+            to your configure switches to have this UAM available.</para>
+          </listitem>
+
+          <listitem>
+            <para>"Kerberos IV"<indexterm>
+                <primary>Kerberos IV</primary>
+
+                <secondary>"Kerberos IV" UAM</secondary>
+              </indexterm><indexterm>
+                <primary>uams_krb4.so</primary>
+
+                <secondary>"Kerberos IV" UAM</secondary>
+              </indexterm>/"AFS Kerberos"<indexterm>
+                <primary>AFS Kerberos</primary>
+
+                <secondary>"AFS Kerberos" UAM (Kerberos IV)</secondary>
+              </indexterm> UAMs (suitable to use <ulink
+            url="http://web.mit.edu/macdev/KfM/Common/Documentation/faq.html">Kerberos
+            v4 based authentication</ulink> and AFS file servers)</para>
+
+            <para>Use <filename>"--enable-krb4-uam"</filename> at compile time
+            to activate the build of this UAM.</para>
+          </listitem>
+
+          <listitem>
+            <para>"Client Krb v2"<indexterm>
+                <primary>Client Krb v2</primary>
+
+                <secondary>"Client Krb v2" UAM (Kerberos V)</secondary>
+              </indexterm> UAM (Kerberos V, suitable for "Single Sign On"
+            Scenarios with OS X clients -- see below)</para>
+
+            <para><filename>"--enable-krbV-uam"</filename> will provide you
+            with the ability to use this UAM.</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>You can configure which UAMs should be activated by defining
+        "<option>uam list</option>" in <option>Global</option> section.
+        <command>afpd</command> will log which UAMs it's using and if problems
+        occur while activating them in either
+        <filename>netatalk.log</filename> or syslog at startup time.
+        <citerefentry>
+            <refentrytitle>asip-status.pl</refentrytitle>
+
+            <manvolnum>1</manvolnum>
+          </citerefentry> can be used to query the available UAMs of AFP
+        servers as well.</para>
+
+        <para>Having a specific UAM available at the server does not
+        automatically mean that a client can use it. Client-side support is
+        also necessary. For older Macintoshes running Mac OS &lt; X DHCAST128
+        support exists since AppleShare client 3.8.x.</para>
+
+        <para>On OS X, there exist some client-side techniques to make the
+        AFP-client more verbose, so one can have a look what's happening while
+        negotiating the UAMs to use. Compare with this <ulink
+        url="http://article.gmane.org/gmane.network.netatalk.devel/7383/">hint</ulink>.</para>
+      </sect3>
+
+      <sect3>
+        <title>Which UAMs to activate?</title>
+
+        <para>It depends primarily on your needs and on the kind of Mac OS
+        versions you have to support. Basically one should try to use
+        DHCAST128 and DHX2 where possible because of its strength of password
+        encryption.</para>
+
+        <itemizedlist>
+          <listitem>
+            <para>Unless you really have to supply guest access to your
+            server's volumes ensure that you disable "No User Authent" since
+            it might lead accidentally to unauthorized access. In case you
+            must enable guest access take care that you enforce this on a per
+            volume base using the access controls.</para>
+          </listitem>
+
+          <listitem>
+            <para>The "ClearTxt Passwrd" UAM is as bad as it sounds since
+            passwords go unencrypted over the wire. Try to avoid it at both
+            the server's side as well as on the client's. Note: If you want to
+            provide Mac OS 8/9 clients with NetBoot-services then you need
+            uams_cleartext.so since the AFP-client integrated into the Mac's
+            firmware can only deal with this basic form of
+            authentication.</para>
+          </listitem>
+
+          <listitem>
+            <para>Since "Randnum exchange"/"2-Way Randnum exchange" uses only
+            56 bit DES for encryption it should be avoided as well. Another
+            disadvantage is the fact that the passwords have to be stored in
+            cleartext on the server and that it doesn't integrate into both
+            PAM scenarios or classic /etc/shadow (you have to administrate
+            passwords separately by using the <citerefentry>
+                <refentrytitle>afppasswd</refentrytitle>
+
+                <manvolnum>1</manvolnum>
+              </citerefentry> utility, if clients should use these
+            UAMs)</para>
+          </listitem>
+
+          <listitem>
+            <para>"DHCAST128" or "DHX2" should be a good compromise for most
+            people since it combines stronger encryption with PAM
+            integration.</para>
+          </listitem>
+
+          <listitem>
+            <para>Using the Kerberos V<indexterm>
+                <primary>Kerberos V</primary>
+
+                <secondary>"Client Krb v2" UAM</secondary>
+              </indexterm> ("Client Krb v2") UAM, it's possible to implement
+            real single sign on scenarios using Kerberos tickets. The password
+            is not sent over the network. Instead, the user password is used
+            to decrypt a service ticket for the appleshare server. The service
+            ticket contains an encryption key for the client and some
+            encrypted data (which only the appleshare server can decrypt). The
+            encrypted portion of the service ticket is sent to the server and
+            used to authenticate the user. Because of the way that the afpd
+            service principal detection is implemented, this authentication
+            method is vulnerable to man-in-the-middle attacks.</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>For a more detailed overview over the technical implications of
+        the different UAMs, please have a look at Apple's <ulink
+        url="http://developer.apple.com/library/mac/#documentation/Networking/Conceptual/AFP/AFPSecurity/AFPSecurity.html#//apple_ref/doc/uid/TP40000854-CH232-SW1">File
+        Server Security</ulink> pages.</para>
+      </sect3>
+
+      <sect3>
+        <title>Using different authentication sources with specific
+        UAMs</title>
+
+        <para>Some UAMs provide the ability to use different authentication
+        "backends", namely <filename>uams_cleartext.so</filename>,
+        <filename>uams_dhx.so</filename> and
+        <filename>uams_dhx2.so</filename>. They can use either classic Unix
+        passwords from <filename>/etc/passwd</filename>
+        (<filename>/etc/shadow</filename>) or PAM if the system supports that.
+        <filename>uams_cleartext.so</filename> can be symlinked to either
+        <filename>uams_passwd.so</filename> or
+        <filename>uams_pam.so</filename>, <filename>uams_dhx.so</filename> to
+        <filename>uams_dhx_passwd.so</filename> or
+        <filename>uams_dhx_pam.so</filename> and
+        <filename>uams_dhx2.so</filename> to
+        <filename>uams_dhx2_passwd.so</filename> or
+        <filename>uams_dhx2_pam.so</filename>.</para>
+
+        <para>So, if it looks like this in Netatalk's UAMs folder (per default
+        <filename>/etc/netatalk/uams/</filename>):<programlisting>uams_clrtxt.so -&gt; uams_pam.so
+uams_dhx.so -&gt; uams_dhx_pam.so
+uams_dhx2.so -&gt; uams_dhx2_pam.so</programlisting> then you're using PAM,
+        otherwise classic Unix passwords. The main advantage of using PAM is
+        that one can integrate Netatalk in centralized authentication
+        scenarios, eg. via LDAP, NIS and the like. Please always keep in mind
+        that the protection of your user's login credentials in such scenarios
+        also depends on the strength of encryption that the UAM in question
+        supplies. So think about eliminating weak UAMs like "ClearTxt Passwrd"
+        and "Randnum exchange" completely from your network.</para>
+      </sect3>
+
+      <sect3>
+        <title>Netatalk UAM overview table</title>
+
+        <para>A small overview of the most common used UAMs.</para>
+
+        <table orient="land">
+          <title>Netatalk UAM overview</title>
+
+          <tgroup align="center" cols="7">
+            <colspec colname="col1" colnum="1" colwidth="0.5*" />
+
+            <colspec colname="uam_guest" colnum="2" colwidth="1*" />
+
+            <colspec colname="uam_clrtxt" colnum="3" colwidth="1*" />
+
+            <colspec colname="uam_randnum" colnum="4" colwidth="1*" />
+
+            <colspec colname="uam_dhx" colnum="5" colwidth="1*" />
+
+            <colspec colname="uam_dhx2" colnum="6" colwidth="1*" />
+
+            <colspec colname="uam_gss" colnum="7" colwidth="1*" />
+
+            <tbody>
+              <row>
+                <entry align="center" rotate="0" valign="middle">UAM</entry>
+
+                <entry>No User Authent<indexterm>
+                    <primary>uams_guest.so</primary>
+
+                    <secondary>"No User Authent" UAM (guest
+                    access)</secondary>
+                  </indexterm></entry>
+
+                <entry>Cleartxt Passwrd<indexterm>
+                    <primary>uams_cleartxt.so</primary>
+
+                    <secondary>"Cleartxt Passwrd" UAM</secondary>
+                  </indexterm></entry>
+
+                <entry>(2-Way) Randnum exchange<indexterm>
+                    <primary>uams_randnum.so</primary>
+
+                    <secondary>"(2-Way) Randnum exchange" UAM</secondary>
+                  </indexterm></entry>
+
+                <entry>DHCAST128<indexterm>
+                    <primary>uams_dhx.so</primary>
+
+                    <secondary>"DHCAST128" UAM</secondary>
+                  </indexterm></entry>
+
+                <entry>DHX2<indexterm>
+                    <primary>uams_dhx2.so</primary>
+
+                    <secondary>"DHX2" UAM</secondary>
+                  </indexterm></entry>
+
+                <entry>Client Krb v2<indexterm>
+                    <primary>uams_gss.so</primary>
+
+                    <secondary>"Client Krb v2" UAM (Kerberos V)</secondary>
+                  </indexterm></entry>
+              </row>
+
+              <row>
+                <entry align="center" rotate="0" valign="middle">pssword
+                length</entry>
+
+                <entry>guest access</entry>
+
+                <entry>max. 8 characters</entry>
+
+                <entry>max. 8 characters</entry>
+
+                <entry>max. 64 characters</entry>
+
+                <entry>max. 256 characters</entry>
+
+                <entry>Kerberos tickets</entry>
+              </row>
+
+              <row>
+                <entry align="center" rotate="0" valign="middle">Client
+                support</entry>
+
+                <entry>built-in into all Mac OS versions</entry>
+
+                <entry>built-in in all Mac OS versions except 10.0. Has to be
+                activated explicitly in recent Mac OS X versions</entry>
+
+                <entry>built-in into almost all Mac OS versions</entry>
+
+                <entry>built-in since AppleShare client 3.8.4, available as a
+                plug-in for 3.8.3, integrated in Mac OS X' AFP client</entry>
+
+                <entry>built-in since Mac OS X 10.2</entry>
+
+                <entry>built-in since Mac OS X 10.2</entry>
+              </row>
+
+              <row>
+                <entry align="center" rotate="0"
+                valign="middle">Encryption</entry>
+
+                <entry>Enables guest access without authentication between
+                client and server.</entry>
+
+                <entry>Password will be sent in cleartext over the wire. Just
+                as bad as it sounds, therefore avoid at all if possible (note:
+                providing NetBoot services requires the ClearTxt UAM)</entry>
+
+                <entry>8-byte random numbers are sent over the wire,
+                comparable with DES, 56 bits. Vulnerable to offline dictionary
+                attack. Requires passwords in clear on the server.</entry>
+
+                <entry>Password will be encrypted with 128 bit SSL, user will
+                be authenticated against the server but not vice versa.
+                Therefor weak against man-in-the-middle attacks.</entry>
+
+                <entry>Password will be encrypted using libgcrypt with CAST
+                128 in CBC mode. User will be authenticated against the server
+                but not vice versa. Therefor weak against man-in-the-middle
+                attacks.</entry>
+
+                <entry>Password is not sent over the network. Due to the
+                service principal detection method, this authentication method
+                is vulnerable to man-in-the-middle attacks.</entry>
+              </row>
+
+              <row>
+                <entry align="center" rotate="0" valign="middle">Server
+                support</entry>
+
+                <entry align="center" valign="middle">uams_guest.so</entry>
+
+                <entry align="center" valign="middle">uams_cleartxt.so</entry>
+
+                <entry align="center" valign="middle">uams_randnum.so</entry>
+
+                <entry align="center" valign="middle">uams_dhx.so</entry>
+
+                <entry align="center" valign="middle">uams_dhx2.so</entry>
+
+                <entry align="center" valign="middle">uams_gss.so</entry>
+              </row>
+
+              <row>
+                <entry align="center" rotate="0" valign="middle">Password
+                storage method</entry>
+
+                <entry align="center" valign="middle">None</entry>
+
+                <entry align="center" valign="middle">Either /etc/passwd
+                (/etc/shadow) or PAM</entry>
+
+                <entry align="center" valign="middle">Passwords stored in
+                clear text in a separate text file</entry>
+
+                <entry align="center" valign="middle">Either /etc/passwd
+                (/etc/shadow) or PAM</entry>
+
+                <entry align="center" valign="middle">Either /etc/passwd
+                (/etc/shadow) or PAM</entry>
+
+                <entry align="center" valign="middle">At the Kerberos Key
+                Distribution Center*</entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+
+        <para>* Have a look at this <ulink
+        url="http://cryptnet.net/fdp/admin/kerby-infra/en/kerby-infra.html">Kerberos
+        overview</ulink></para>
+      </sect3>
+
+      <sect3 id="sshtunnel">
+        <title>SSH tunneling</title>
+
+        <para>Tunneling and all sort of VPN stuff has nothing to do with AFP
+        authentication and UAMs in general. But since Apple introduced an
+        option called "Allow Secure Connections Using SSH" and many people
+        tend to confuse both things, we'll speak about that here too.</para>
+
+        <sect4 id="manualsshtunnel">
+          <title>Manually tunneling an AFP session</title>
+
+          <para>This works since the first AFP servers that spoke "AFP over
+          TCP" appeared in networks. One simply tunnels the remote server's
+          AFP port to a local port different than 548 and connects locally to
+          this port afterwards. On OS X this can be done by</para>
+
+          <programlisting>ssh -l $USER $SERVER -L 10548:127.0.0.1:548 sleep 3000</programlisting>
+
+          <para>After establishing the tunnel one will use
+          <filename>"afp://127.0.0.1:10548"</filename> in the "Connect to
+          server" dialog. All AFP traffic including the initial connection
+          attempts will be sent encrypted over the wire since the local AFP
+          client will connect to the Mac's local port 10548 which will be
+          forwarded to the remote server's AFP port (we used the default 548)
+          over SSH.</para>
+
+          <para>These sorts of tunnels are an ideal solution if you've to
+          access an AFP server providing weak authentications mechanisms
+          through the Internet without having the ability to use a "real" VPN.
+          Note that you can let <command>ssh</command> compress the data by
+          using its "-C" switch and that the tunnel endpoints can be different
+          from both AFP client and server (compare with the SSH documentation
+          for details).</para>
+        </sect4>
+
+        <sect4 id="autosshtunnel">
+          <title>Automatically establishing a tunneled AFP connection</title>
+
+          <para>From Mac OS X 10.2 to 10.4, Apple added an "Allow Secure
+          Connections Using SSH" checkbox to the "Connect to Server" dialog.
+          The idea behind: When the server signals that it can be contacted by
+          SSH then Mac OS X' AFP client tries to establish the tunnel and
+          automagically sends all AFP traffic through it.</para>
+
+          <para>But it took until the release of Mac OS X 10.3 that this
+          feature worked the first time... partly. In case, the SSH tunnel
+          can't be established the AFP client <emphasis
+          role="strong">silently</emphasis> fell back to an unencrypted AFP
+          connection attempt.</para>
+
+          <para>Netatalk's afpd will report that it is capable of handling SSH
+          tunneled AFP requests, when both "<option>advertise ssh</option>"
+          and "<option>fqdn</option>" options are set in
+          <option>Global</option> section (double check with <citerefentry>
+              <refentrytitle>asip-status.pl</refentrytitle>
+
+              <manvolnum>1</manvolnum>
+            </citerefentry> after you restarted afpd when you made changes to
+          the settings). But there are a couple of reasons why you don't want
+          to use this option at all:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para>Tunneling TCP over TCP (as SSH does) is not the best idea.
+              There exist better solutions like VPNs based on the IP
+              layer.</para>
+            </listitem>
+
+            <listitem>
+              <para>Since this SSH kludge isn't a normal UAM that integrates
+              directly into the AFP authentication mechanisms but instead uses
+              a single flag signalling clients whether they can <emphasis
+              role="strong">try</emphasis> to establish a tunnel or not, it
+              makes life harder to see what's happening when things go
+              wrong.</para>
+            </listitem>
+
+            <listitem>
+              <para>You cannot control which machines are logged on by
+              Netatalk tools like a <command>macusers</command> since all
+              connection attempts seem to be made from localhost.</para>
+            </listitem>
+
+            <listitem>
+              <para>On the other side you've to limit access to afpd to
+              localhost only (TCP wrappers) when you want to ensure that all
+              AFP sessions are SSH encrypted or...</para>
+            </listitem>
+
+            <listitem>
+              <para>...when you're using 10.2 - 10.3.3 then you get the
+              opposite of what you'd expect: potentially unencrypted AFP
+              communication (including logon credentials) on the network
+              without a single notification that establishing the tunnel
+              failed. Apple fixed that not until Mac OS X 10.3.4.</para>
+            </listitem>
+
+            <listitem>
+              <para>Encrypting all AFP sessions via SSH can lead to a
+              significantly higher load on the Netatalk server</para>
+            </listitem>
+          </itemizedlist>
+        </sect4>
+      </sect3>
+    </sect2>
+
+    <sect2 id="acls">
+      <title>ACL Support<indexterm>
+          <primary>ACLs</primary>
+        </indexterm></title>
+
+      <para>ACL support for AFP is implemented for ZFS ACLs on Solaris and
+      derived platforms and for POSIX 1e ACLs on Linux.</para>
+
+      <sect3>
+        <title>Configuration</title>
+
+        <para>For a basic mode of operation there's nothing to configure.
+        Netatalk reads ACLs on the fly and calculates effective permissions
+        which are then send to the AFP client via the so called
+        UARights<indexterm>
+            <primary>UARights</primary>
+          </indexterm> permission bits. On a Mac, the Finder uses these bits
+        to adjust permission in Finder windows. For example folder whos UNIX
+        mode would only result in in read-only permissions for a user will not
+        be displayed with a read-only icon and the user will be able to write
+        to the folder given the folder has an ACL giving the user write
+        access.</para>
+
+        <para>By default, the effective permission of the authenticated user
+        are only mapped to the mentioned UARights<indexterm>
+            <primary>UARights</primary>
+          </indexterm>permission structure, not the UNIX mode. You can adjust
+        this behaviour with the configuration option <link
+        linkend="map_acls">map acls</link>.</para>
+
+        <para>However, neither in Finder "Get Info" windows nor in Terminal
+        will you be able to see the ACLs, that's a result of how ACLs in OS X
+        are designed. If you want to be able to display ACLs on the client,
+        things get more involved as you must then setup both client and server
+        to be part on a authentication domain (directory service, eg LDAP,
+        OpenDirectory). The reason is, that in OS X ACLs are bound to UUIDs,
+        not just uid's or gid's. Therefor afpd must be able to map every
+        filesystem uid and gid to a UUID so that it can return the server side
+        ACLs which are bound to UNIX uid and gid mapped to OS X UUIDs.</para>
+
+        <para>Netatalk can query a directory server using LDAP queries. Either
+        the directory server already provides an UUID attribute for user and
+        groups (Active Directory, Open Directory) or you reuse an unused
+        attribute (or add a new one) to you directory server (eg
+        OpenLDAP).</para>
+
+        <para>In detail:</para>
+
+        <orderedlist>
+          <listitem>
+            <para>For Solaris/ZFS: ZFS Volumes</para>
+
+            <para>You should configure a ZFS ACL know for any volume you want
+            to use with Netatalk:</para>
+
+            <screen>aclinherit = passthrough
+aclmode = passthrough</screen>
+
+            <para>For an explanation of what this knob does and how to apply
+            it, check your hosts ZFS documentation (eg man zfs).</para>
+          </listitem>
+
+          <listitem>
+            <para>Authentication Domain</para>
+
+            <para>Your server and the clients must be part of a security
+            association where identity data is coming from a common source.
+            ACLs in Darwin are based on UUIDs and so is the ACL specification
+            in AFP 3.2. Therefor your source of identity data has to provide
+            an attribute for every user and group where a UUID is stored as a
+            ASCII string. In other words:</para>
+
+            <itemizedlist>
+              <listitem>
+                <para>you need an Open Directory Server or an LDAP server
+                where you store UUIDs in some attribute</para>
+              </listitem>
+
+              <listitem>
+                <para>your clients must be configured to use this
+                server</para>
+              </listitem>
+
+              <listitem>
+                <para>your server should be configured to use this server via
+                nsswitch and PAM</para>
+              </listitem>
+
+              <listitem>
+                <para>configure Netatalk via the special <link
+                linkend="acl_options">LDAP options for ACLs</link> in <link
+                linkend="afp.conf.5">afp.conf</link> so that Netatalk is able
+                to retrieve the UUID for users and groups via LDAP search
+                queries</para>
+              </listitem>
+            </itemizedlist>
+          </listitem>
+        </orderedlist>
+      </sect3>
+
+      <sect3>
+        <title>OS X ACLs</title>
+
+        <para>With Access Control Lists (ACLs) Mac OS X offers a powerful
+        extension of the traditional UNIX permissions model. An ACL is an
+        ordered list of Access Control Entries (ACEs) explicitly granting or
+        denying a set of permissions to a given user or group.</para>
+
+        <para>Unlike UNIX permissions, which are bound to user or group IDs,
+        ACLs are tied to UUIDs. For this reason accessing an object's ACL
+        requires server and client to use a common directory service which
+        translates between UUIDs and user/group IDs.</para>
+
+        <para>ACLs and UNIX permissions interact in a rather simple way. As
+        ACLs are optional UNIX permissions act as a default mechanism for
+        access control. Changing an objects's UNIX permissions will leave it's
+        ACL intact and modifying an ACL will never change the object's UNIX
+        permissions. While doing access checks, OS X first examines an
+        object's ACL evaluating ACEs in order until all requested rights have
+        been granted, a requested right has been explicitly denied by an ACE
+        or the end of the list has been reached. In case there is no ACL or
+        the permissions granted by the ACL are not sufficient to fulfill the
+        request, OS X next evaluates the object's UNIX permissions. Therefore
+        ACLs always have precedence over UNIX permissions.</para>
+      </sect3>
+
+      <sect3>
+        <title>ZFS ACLs</title>
+
+        <para>ZFS ACLs closely match OS X ACLs. Both offer mostly identical
+        fine grained permissions and inheritance settings.</para>
+      </sect3>
+
+      <sect3>
+        <title>POSIX ACLs</title>
+
+        <sect4>
+          <title>Overview</title>
+
+          <para>Compared to OS X or NFSv4 ACLs, Posix ACLs represent a
+          different, less versatile approach to overcome the limitations of
+          the traditional UNIX permissions. Implementations are based on the
+          withdrawn Posix 1003.1e standard.</para>
+
+          <para>The standard defines two types of ACLs. Files and directories
+          can have access ACLs which are consulted for access checks.
+          Directories can also have default ACLs irrelevant to access checks.
+          When a new object is created inside a directory with a default ACL,
+          the default ACL is applied to the new object as it's access ACL.
+          Subdirectories inherit default ACLs from their parent. There are no
+          further mechanisms of inheritance control. </para>
+
+          <para>Architectural differences between Posix ACLs and OS X ACLs
+          especially involve:</para>
+
+          <para><itemizedlist>
+              <listitem>
+                <para>No fine-granular permissions model. Like UNIX
+                permissions Posix ACLs only differentiate between read, write
+                and execute permissions.</para>
+              </listitem>
+
+              <listitem>
+                <para>Entries within an ACL are unordered.</para>
+              </listitem>
+
+              <listitem>
+                <para>Posix ACLs can only grant rights. There is no way to
+                explicitly deny rights by an entry.</para>
+              </listitem>
+
+              <listitem>
+                <para>UNIX permissions are integrated into an ACL as special
+                entries.</para>
+              </listitem>
+            </itemizedlist></para>
+
+          <para>Posix 1003.1e defines 6 different types of ACL entries. The
+          first three types are used to integrate standard UNIX permissions.
+          They form a minimal ACL, their presence is mandatory and only one
+          entry of each type is allowed within an ACL.</para>
+
+          <para><itemizedlist>
+              <listitem>
+                <para>ACL_USER_OBJ: the owner's access rights.</para>
+              </listitem>
+
+              <listitem>
+                <para>ACL_GROUP_OBJ: the owning group's access rights.</para>
+              </listitem>
+
+              <listitem>
+                <para>ACL_OTHER: everybody's access rights.</para>
+              </listitem>
+            </itemizedlist></para>
+
+          <para>The remaining entry types expand the traditional permissions
+          model:</para>
+
+          <para><itemizedlist>
+              <listitem>
+                <para>ACL_USER: grants access rights to a certain user.</para>
+              </listitem>
+
+              <listitem>
+                <para>ACL_GROUP: grants access rights to a certain
+                group.</para>
+              </listitem>
+
+              <listitem>
+                <para>ACL_MASK: limits the maximum access rights which can be
+                granted by entries of type ACL_GROUP_OBJ, ACL_USER and
+                ACL_GROUP. As the name suggests, this entry acts as a mask.
+                Only one ACL_MASK entry is allowed per ACL. If an ACL contains
+                ACL_USER or ACL_GROUP entries, an ACL_MASK entry must be
+                present too, otherwise it is optional.</para>
+              </listitem>
+            </itemizedlist></para>
+
+          <para>In order to maintain compatibility with applications not aware
+          of ACLs, Posix 1003.1e changes the semantics of system calls and
+          utilities which retrieve or manipulate an objects UNIX permissions.
+          In case an object only has a minimal ACL, the group permissions bits
+          of the UNIX permissions correspond to the value of the ACL_GROUP_OBJ
+          entry.</para>
+
+          <para>However, if the ACL also contains an ACL_MASK entry, the
+          behavior of those system calls and utilities is different. The group
+          permissions bits of the UNIX permissions correspond to the value of
+          the ACL_MASK entry, i. e. calling "chmod g-w" will not only revoke
+          write access for the group, but for all entities which have been
+          granted write access by ACL_USER or ACL_GROUP entries.</para>
+        </sect4>
+
+        <sect4>
+          <title>Mapping POSIX ACLs to OS X ACLs</title>
+
+          <para>When a client wants to read an object's ACL, afpd maps it's
+          Posix ACL onto an equivalent OS X ACL. Writing an object's ACL
+          requires afpd to map an OS X ACL onto a Posix ACL. Due to
+          architectural restrictions of Posix ACLs, it is usually impossible
+          to find an exact mapping so that the result of the mapping process
+          will be an approximation of the original ACL's semantic.</para>
+
+          <para><itemizedlist>
+              <listitem>
+                <para>afpd silently discard entries which deny a set of
+                permissions because they they can't be represented within the
+                Posix architecture. </para>
+              </listitem>
+
+              <listitem>
+                <para>As entries within Posix ACLs are unordered, it is
+                impossible to preserve order.</para>
+              </listitem>
+
+              <listitem>
+                <para>Inheritance control is subject to severe limitations as
+                well:<itemizedlist>
+                    <listitem>
+                      <para>Entries with the only_inherit flag set will only
+                      become part of the directory's default ACL.</para>
+                    </listitem>
+
+                    <listitem>
+                      <para>Entries with at least one of the flags
+                      file_inherit, directory_inherit or limit_inherit set,
+                      will become part of the directory's access and default
+                      ACL, but the restrictions they impose on inheritance
+                      will be ignored.</para>
+                    </listitem>
+                  </itemizedlist></para>
+              </listitem>
+
+              <listitem>
+                <para>The lack of a fine-granular permission model on the
+                Posix side will normally result in an increase of granted
+                permissions.</para>
+              </listitem>
+            </itemizedlist></para>
+
+          <para>As OS X clients aren't aware of the Posix 1003.1e specific
+          relationship between UNIX permissions and ACL_MASK, afpd does not
+          expose this feature to the client to avoid compatibility issues and
+          handles *unix permissions and ACLs the same way as Apple's reference
+          implementation of AFP does. When an object's UNIX permissions are
+          requested, afpd calculates proper group rights and returns the
+          result together with the owner's and everybody's access rights to
+          the caller via "permissions" and "ua_permissions" members of the
+          FPUnixPrivs structure (see Apple Filing Protocol Reference, page
+          181). Changing an object's permissions, afpd always updates
+          ACL_USER_OBJ, ACL_GROUP_OBJ and ACL_OTHERS. If an ACL_MASK entry is
+          present too, afpd recalculates it's value so that the new group
+          rights become effective and existing entries of type ACL_USER or
+          ACL_GROUP stay intact.</para>
+        </sect4>
+      </sect3>
+    </sect2>
+
+    <sect2 id="fce">
+      <title>Filesystem Change Events<indexterm>
+          <primary>FCE</primary>
+        </indexterm></title>
+
+      <para>Netatalk includes a nifty filesystem change event mechanism where
+      afpd processes notfiy interested listeners about certain filesystem
+      event by UDP network datagrams.</para>
+
+      <para>For the format of the UDP packets and for an example C application
+      that demonstrates how to use these in a listener, take a look at the
+      Netatalk sourcefile <filename>bin/misc/fce.c</filename>.</para>
+
+      <para>The currently supported FCE events are<itemizedlist>
+          <listitem>
+            <para>file modification (fmod)</para>
+          </listitem>
+
+          <listitem>
+            <para>file deletion (fdel)</para>
+          </listitem>
+
+          <listitem>
+            <para>directory deletion (ddel)</para>
+          </listitem>
+
+          <listitem>
+            <para>file creation (fcre)</para>
+          </listitem>
+
+          <listitem>
+            <para>directory deletion (ddel)</para>
+          </listitem>
+        </itemizedlist></para>
+
+      <para>For details on the available simple configuration options take a
+      look at <filename><link
+      linkend="fceconf">afp.conf</link></filename>.</para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Starting and stopping Netatalk</title>
+
+    <para>The Netatalk distribution comes with several operating system
+    specific startup script templates that are tailored according to the
+    options given to the "configure" script before compiling. Currently,
+    templates are provided for RedHat (sysv style), RedHat (systemd style),
+    SUSE (sysv style), SUSE (systemd style), Gentoo, NetBSD, Debian and
+    Solaris. You can select to install the generated startup script(s)
+    <indexterm>
+        <primary>Startscript</primary>
+
+        <secondary>startup script</secondary>
+      </indexterm> by specifying a system type to "configure". To
+    automatically install startup scripts give one of the available
+    <option>--with-init-style</option> option to "configure".</para>
+
+    <para>Since new releases of Linux distributions appear all the time and
+    the startup procedure for the other systems mentioned above might change
+    as well, it is probably a good idea to not blindly install a startup
+    script but to look at it first to see if it will work on your system. If
+    you use Netatalk as part of a fixed setup, like a Linux distribution, an
+    RPM or a BSD package, things will probably have been arranged properly for
+    you. The following therefore applies mostly for people who have compiled
+    Netatalk themselves.</para>
+
+    <para>The following daemon need to be started by whatever startup script
+    mechanism is used:</para>
+
+    <itemizedlist>
+      <listitem>
+        <para>netatalk<indexterm>
+            <primary>netatalk</primary>
+          </indexterm></para>
+      </listitem>
+    </itemizedlist>
+
+    <para>Additionally, make sure that the configuration file
+    <filename>afp.conf</filename> is in the right place.</para>
+  </sect1>
+</chapter>
diff --git a/doc/manual/install.xml b/doc/manual/install.xml
new file mode 100644 (file)
index 0000000..a64b384
--- /dev/null
@@ -0,0 +1,347 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="installation">
+  <chapterinfo>
+    <date>24.8.2012</date>
+  </chapterinfo>
+
+  <title>Installation</title>
+
+  <warning>
+    <para>If you have previously used an older version of Netatalk, please
+    read the chapter about <link linkend="upgrade">upgrading</link> first
+    !!!</para>
+  </warning>
+
+  <para></para>
+
+  <sect1>
+    <title>How to obtain Netatalk</title>
+
+    <para>Please have a look at the netatalk page on sourceforge for the most
+    recent informations on this issue.</para>
+
+    <para><ulink
+    url="http://sourceforge.net/projects/netatalk/">http://sourceforge.net/projects/netatalk/</ulink></para>
+
+    <sect2>
+      <title>Binary packages</title>
+
+      <para>Binary packages of Netatalk are included in some Linux and UNIX
+      distributions. You might want to have a look at the usual locations,
+      too.</para>
+
+      <para>Ubuntu package: <ulink
+      url="https://launchpad.net/ubuntu">https://launchpad.net/ubuntu
+      </ulink></para>
+
+      <para>Debian package: <ulink
+      url="http://packages.debian.org/">http://packages.debian.org/
+      </ulink></para>
+
+      <para>various RPM package: <ulink
+      url="http://rpmfind.net/">http://rpmfind.net/ </ulink></para>
+
+      <para>Fedora/RHEL package: <ulink
+      url="http://koji.fedoraproject.org/koji/search">http://koji.fedoraproject.org/koji/search
+      </ulink></para>
+
+      <para>Gentoo package: <ulink
+      url="http://packages.gentoo.org/">http://packages.gentoo.org/
+      </ulink></para>
+
+      <para>openSUSE package: <ulink
+      url="http://software.opensuse.org/">http://software.opensuse.org/
+      </ulink></para>
+
+      <para>Solaris package: <ulink
+      url="http://www.blastwave.org/">http://www.blastwave.org/
+      </ulink></para>
+
+      <para>FreeBSD ports: <ulink
+      url="http://www.freebsd.org/ports/index.html">http://www.freebsd.org/ports/index.html
+      </ulink></para>
+
+      <para>NetBSD pkgsrc: <ulink
+      url="http://pkgsrc.se/search.php">http://pkgsrc.se/search.php
+      </ulink></para>
+
+      <para>OpenBSD ports:<ulink
+      url="http://openports.se/search.php">http://openports.se/search.php
+      </ulink></para>
+
+      <para>etc.<indexterm>
+          <primary>RPM</primary>
+
+          <secondary>Red Hat Package Manager package</secondary>
+        </indexterm><indexterm>
+          <primary>Deb</primary>
+
+          <secondary>Debian package</secondary>
+        </indexterm><indexterm>
+          <primary>Ports</primary>
+
+          <secondary>FreeBSD port</secondary>
+        </indexterm></para>
+    </sect2>
+
+    <sect2>
+      <title>Source packages</title>
+
+      <sect3>
+        <title>Tarballs</title>
+
+        <para>Prepacked tarballs in .tar.gz and tar.bz2 format are available
+        on the netatalk page on <ulink
+        url="http://netatalk.sourceforge.net/">sourceforge</ulink>.</para>
+      </sect3>
+
+      <sect3>
+        <title>Git</title>
+
+        <para>Downloading the Git repository can be done quickly and
+        easily.</para>
+
+        <orderedlist>
+          <listitem>
+            <para>Make sure you have Git installed. <command>which
+            git</command> should produce a path to git.</para>
+
+            <screen><prompt>$&gt;</prompt> <userinput>which git</userinput>
+<computeroutput>/usr/bin/git</computeroutput></screen>
+          </listitem>
+
+          <listitem>
+            <para>If you don't have one make a source directory.
+            <command>cd</command> to this directory.</para>
+
+            <screen><prompt>$&gt;</prompt> <userinput>mkdir /path/to/new/source/dir</userinput>
+<prompt>$&gt;</prompt> <userinput>cd /path/to/new/source/dir</userinput></screen>
+          </listitem>
+
+          <listitem>
+            <para>Now get the source:</para>
+
+            <screen><prompt>$&gt;</prompt> <userinput>git clone git://git.code.sf.net/p/netatalk/code netatalk-code
+</userinput><computeroutput>Initialized empty Git repository in /path/to/new/source/dir/netatalk/.git/
+remote: Counting objects: 2503, done.
+...
+</computeroutput></screen>
+
+            <para>This will create a local directory called "netatalk-code"
+            containing a complete and fresh copy of the whole Netatalk source
+            from the Git repository.</para>
+          </listitem>
+
+          <listitem>
+            <para>In order to keep your repository copy updated, occasionally
+            run:</para>
+
+            <screen><prompt>$&gt;</prompt> <userinput>git pull</userinput></screen>
+          </listitem>
+
+          <listitem>
+            <para>Now <command>cd</command> to the netatalk directory and run
+            <command>./bootstrap</command>. This will create the
+            <filename>configure</filename> script required in the next
+            step.</para>
+
+            <screen><prompt>$&gt;</prompt> <userinput>./bootstrap</userinput></screen>
+          </listitem>
+        </orderedlist>
+
+        <para></para>
+      </sect3>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Compiling Netatalk</title>
+
+    <sect2>
+      <title>Prerequisites</title>
+
+      <sect3>
+        <title>Required third party software</title>
+
+        <itemizedlist>
+          <listitem>
+            <para>Berkeley DB<indexterm>
+                <primary>BDB</primary>
+
+                <secondary>Berkeley DB</secondary>
+              </indexterm>.</para>
+
+            <para>At the time of writing, the following versions are
+            supported:</para>
+
+            <itemizedlist>
+              <listitem>
+                <para>minimum 4.6.x</para>
+              </listitem>
+            </itemizedlist>
+
+            <para>In case Berkeley DB is not installed on your system, please
+            download it from:</para>
+
+            <para><ulink
+            url="http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html">
+            http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html</ulink></para>
+
+            <para>and follow the <link linkend="build-bdb">installation
+            instructions</link>.</para>
+          </listitem>
+
+          <listitem>
+            <para>Libgcrypt</para>
+
+            <para>Required for OS X 10.7 and later. Libgcrypt is needed for
+            DHX2.</para>
+
+            <para>Libgcrypt can be downloaded from: <ulink
+            url="http://directory.fsf.org/wiki/Libgcrypt">
+            http://directory.fsf.org/wiki/Libgcrypt</ulink>.</para>
+          </listitem>
+        </itemizedlist>
+      </sect3>
+
+      <sect3>
+        <title>Optional third party software</title>
+
+        <para>Netatalk can use the following third party software to enhance
+        it's functionality.</para>
+
+        <itemizedlist>
+          <listitem>
+            <para>mDNSresponderPOSIX or Avahi for Bonjour (aka
+            Zeroconf)</para>
+
+            <para>Mac OS X 10.2 and later use Bonjour (aka Zeroconf) for
+            service discovery.</para>
+
+            <para>Avahi must be build with DBUS support (
+            <userinput>--enable-dbus</userinput>).</para>
+
+            <para>You can download Avahi from: <ulink
+            url="http://www.avahi.org/">http://www.avahi.org/</ulink>.</para>
+
+            <para>You can download mDNSresponder from: <ulink
+            url="http://opensource.apple.com/tarballs/mDNSResponder/">http://opensource.apple.com/tarballs/mDNSResponder/</ulink>.</para>
+          </listitem>
+
+          <listitem>
+            <para>TCP wrappers</para>
+
+            <para>Wietse Venema's network logger, also known as TCPD or
+            LOG_TCP.</para>
+
+            <para>Security options are: access control per host, domain and/or
+            service; detection of host name spoofing or host address spoofing;
+            booby traps to implement an early-warning system.</para>
+
+            <para>TCP Wrappers can be downloaded from: <ulink
+            url="ftp://ftp.porcupine.org/pub/security">ftp://ftp.porcupine.org/pub/security</ulink>/</para>
+          </listitem>
+
+          <listitem>
+            <para>PAM<indexterm>
+                <primary>PAM</primary>
+
+                <secondary>Pluggable Authentication Modules</secondary>
+              </indexterm></para>
+
+            <para>PAM provides a flexible mechanism for authenticating users.
+            PAM was invented by SUN<indexterm>
+                <primary>SUN</primary>
+
+                <secondary>Sun Microsystems</secondary>
+              </indexterm> Microsystems. Linux-PAM is a suite of shared
+            libraries that enable the local system administrator to choose how
+            applications authenticate users.</para>
+
+            <para>You can get the Linux PAM documentation and sources from
+            <ulink
+            url="http://www.kernel.org/pub/linux/libs/pam/">http://www.kernel.org/pub/linux/libs/pam/</ulink>.</para>
+          </listitem>
+
+          <listitem>
+            <para>iconv</para>
+
+            <para>iconv provides conversion routines for many character
+            encodings. Netatalk uses it to provide charsets it does not have
+            built in conversions for, like ISO-8859-1. On glibc systems,
+            Netatalk can use the glibc provided iconv implementation.
+            Otherwise you can use the GNU libiconv implementation.</para>
+
+            <para>You can download GNU libiconv from: <olink><ulink
+            url="http://www.gnu.org/software/libiconv/">http://www.gnu.org/software/libiconv/</ulink></olink>.</para>
+          </listitem>
+        </itemizedlist>
+      </sect3>
+    </sect2>
+
+    <sect2 id="compiling-netatalk">
+      <title>Compiling<indexterm>
+          <primary>Compile</primary>
+
+          <secondary>Compiling Netatalk from Source</secondary>
+        </indexterm> Netatalk</title>
+
+      <sect3>
+        <title>Configuring the build</title>
+
+        <para>To build the binaries, first run the program
+        <command>./configure</command> in the source directory. This should
+        automatically configure Netatalk for your operating system. If you
+        have unusual needs, then you may wish to run</para>
+
+        <screen>$&gt; <userinput>./configure --help</userinput></screen>
+
+        <para>to see what special options you can enable.</para>
+
+        <para>The most used configure options are:</para>
+
+        <itemizedlist>
+          <listitem>
+            <para><option>--with-init-style</option>=redhat-sysv|redhat-systemd|suse-sysv|suse-systemd|gentoo|netbsd|debian|solaris|systemd</para>
+
+            <para>This option helps netatalk to determine where to install the
+            start scripts.</para>
+          </listitem>
+
+          <listitem>
+            <para><option>--with-bdb</option>=<replaceable>/path/to/bdb/installation/</replaceable></para>
+
+            <para>In case you installed Berkeley DB in a non-standard
+            location, you will <emphasis>have</emphasis> to give the install
+            location to netatalk, using this switch.</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>Now run configure with any options you need</para>
+
+        <screen><prompt>$&gt;</prompt> <userinput>./configure [arguments]</userinput></screen>
+
+        <para>Configure will end up in an overview showing the settings the
+        Netatalk Makefiles have been created with.</para>
+
+        <para>If this step fails please visit the <ulink
+        url="http://netatalk.sourceforge.net/wiki/index.php/Troubleshooting">troubleshooting
+        guide</ulink>.</para>
+
+        <para>Next, running</para>
+
+        <screen><prompt>$&gt;</prompt> <userinput>make</userinput></screen>
+
+        <para>should produce the Netatalk binaries (this step can take several
+        minutes to complete).</para>
+
+        <para>When the process finished you can use</para>
+
+        <screen><prompt>$&gt;</prompt> <userinput>make install</userinput></screen>
+
+        <para>to install the binaries and documentation (must be done as
+        "root" when using default locations).</para>
+      </sect3>
+    </sect2>
+  </sect1>
+</chapter>
diff --git a/doc/manual/intro.xml b/doc/manual/intro.xml
new file mode 100644 (file)
index 0000000..0b70a9a
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="intro">
+  <title>Introduction to Netatalk</title>
+
+  <para>Netatalk is an OpenSource software package, that can be used to turn
+  a *NIX machine into an extremely high-performance and
+  reliable file server for Macintosh computers.</para>
+
+  <para>Using Netatalk's AFP 3.3 compliant file-server leads to significantly
+  higher transmission speeds compared with Macs accessing a server via
+  SaMBa/NFS while providing clients with the best possible user experience
+  (full support for Macintosh metadata, flawlessly supporting mixed
+  environments of classic Mac OS and OS X clients)</para>
+
+</chapter>
diff --git a/doc/manual/manual.xml.in b/doc/manual/manual.xml.in
new file mode 100644 (file)
index 0000000..eab6e62
--- /dev/null
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+
+<!ENTITY Intro SYSTEM "netatalk/intro.xml">
+<!ENTITY Install SYSTEM "netatalk/install.xml">
+<!ENTITY Upgrade SYSTEM "netatalk/upgrade.xml">
+<!ENTITY Configuration SYSTEM "netatalk/configuration.xml">
+
+<!ENTITY ad.1 SYSTEM "man/man1/ad.1.xml">
+<!ENTITY afpd.8 SYSTEM "man/man8/afpd.8.xml">
+<!ENTITY cnid_dbd.8 SYSTEM "man/man8/cnid_dbd.8.xml">
+<!ENTITY cnid_metad.8 SYSTEM "man/man8/cnid_metad.8.xml">
+<!ENTITY afp.conf.5 SYSTEM "man/man5/afp.conf.5.xml">
+<!ENTITY afp_signature.conf.5 SYSTEM "man/man5/afp_signature.conf.5.xml">
+<!ENTITY afp_voluuid.conf.5 SYSTEM "man/man5/afp_voluuid.conf.5.xml">
+<!ENTITY afpldaptest.1 SYSTEM "man/man1/afpldaptest.1.xml">
+<!ENTITY afppasswd.1 SYSTEM "man/man1/afppasswd.1.xml">
+<!ENTITY afpstats.1 SYSTEM "man/man1/afpstats.1.xml">
+<!ENTITY apple_dump.1 SYSTEM "man/man1/apple_dump.1.xml">
+<!ENTITY extmap.conf.5 SYSTEM "man/man5/extmap.conf.5.xml">
+<!ENTITY macusers.1 SYSTEM "man/man1/macusers.1.xml">
+<!ENTITY megatron.1 SYSTEM "man/man1/megatron.1.xml">
+<!ENTITY netatalk.8 SYSTEM "man/man8/netatalk.8.xml">
+<!ENTITY netatalk-config.1 SYSTEM "man/man1/netatalk-config.1.xml">
+<!ENTITY uniconv.1 SYSTEM "man/man1/uniconv.1.xml">
+<!ENTITY asip-status.pl.1 SYSTEM "man/man1/asip-status.pl.1.xml">
+<!ENTITY dbd.1 SYSTEM "man/man1/dbd.1.xml">
+]>
+<book id="netatalk-manual">
+  <title>Netatalk 3.0 Manual</title>
+  
+  <bookinfo>
+    <date>03-24-2013</date>
+    <releaseinfo>@NETATALK_VERSION@</releaseinfo>
+  </bookinfo>
+
+ <?latex \setcounter{page}{3} ?>
+<preface>
+        <title>Legal Notice</title>
+<para>
+This documentation is distributed under the GNU General Public License (GPL) version 2.  
+A copy of the license is included in this documentation, as well as within the Netatalk source
+distribution.  An on-line copy can be found at <ulink
+url="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</ulink>
+</para>
+</preface>
+
+  <?latex \cleardoublepage ?>
+  <!-- Contents -->
+  <toc/>
+  <?latex \cleardoublepage ?>
+  <?latex \pagenumbering{arabic} ?>
+
+  &Intro;
+  <?latex \cleardoublepage ?>
+
+  &Install;
+  <?latex \cleardoublepage ?>
+
+  &Configuration;
+  <?latex \cleardoublepage ?>
+
+  &Upgrade;
+  <?latex \cleardoublepage ?>
+
+  <chapter id="man-pages">
+    <title>Manual Pages</title>
+
+    <para>This is a collection of the man pages delivered with Netatalk.</para>
+
+    &ad.1;
+
+    &afp.conf.5;
+
+    &afp_signature.conf.5;
+
+    &afp_voluuid.conf.5;
+
+    &afpd.8;
+
+    &afpldaptest.1;
+
+    &afppasswd.1;
+
+    &afpstats.1;
+
+    &apple_dump.1;
+
+    &asip-status.pl.1;
+
+    &cnid_dbd.8;
+
+    &cnid_metad.8;
+
+    &dbd.1;
+
+    &extmap.conf.5;
+
+    &macusers.1;
+
+    &megatron.1;
+
+    &netatalk.8;
+
+    &netatalk-config.1;
+
+    &uniconv.1;
+  </chapter>
+  <?latex \cleardoublepage ?>
+
+  <?latex \include{gpl}?>
+  <?latex \cleardoublepage ?>
+
+  <index id="manual-index"><title>Index</title></index>
+</book>
diff --git a/doc/manual/upgrade.xml b/doc/manual/upgrade.xml
new file mode 100644 (file)
index 0000000..ebd1963
--- /dev/null
@@ -0,0 +1,1555 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="upgrade">
+  <chapterinfo>
+    <date>2.15.2013</date>
+
+    <author>
+      <firstname>Frank</firstname>
+
+      <surname>Lahm</surname>
+    </author>
+
+    <pubdate>15 Feb, 2013</pubdate>
+  </chapterinfo>
+
+  <title>Upgrading from Netatalk 2</title>
+
+  <sect1>
+    <title>Overview</title>
+
+    <para>There are two major changes in Netatalk:<orderedlist>
+        <listitem>
+          <para>New configuration file <filename><link
+          linkend="afp.conf.5">afp.conf</link></filename>, obsoleting all
+          previous configuration files</para>
+        </listitem>
+
+        <listitem>
+          <para>New AppleDouble backend "<option>appledouble = ea</option>"
+          which stores Mac metadata and resource forks in extended attributes
+          of the filesystem</para>
+        </listitem>
+      </orderedlist></para>
+
+    <sect2>
+      <title>New configuration</title>
+
+      <para><itemizedlist>
+          <listitem>
+            <para>ini style syntax (like Samba’s smb.conf)</para>
+          </listitem>
+
+          <listitem>
+            <para>one to rule them all: configure AFP settings and volumes in
+            one file</para>
+          </listitem>
+
+          <listitem>
+            <para>obsoletes <filename>afpd.conf</filename>,
+            <filename>netatalk.conf</filename>,
+            <filename>AppleVolumes.default</filename> and
+            <filename>afp_ldap.conf</filename></para>
+          </listitem>
+        </itemizedlist><warning>
+          <para>most option names have changed, read the full manpage <link
+          linkend="afp.conf.5">afp.conf</link> for details</para>
+        </warning></para>
+    </sect2>
+
+    <sect2>
+      <title>New AppleDouble backend</title>
+
+      <para>New AppleDouble backend "<option>appledouble = ea</option>" which
+      stores Mac metadata and resource forks in extended attributes of the
+      filesystem.<itemizedlist>
+          <listitem>
+            <para>default backend (!)</para>
+          </listitem>
+
+          <listitem>
+            <para>requires a filesystem with Extended Attributes, fallback is
+            "<option>appledouble = v2</option>"</para>
+          </listitem>
+
+          <listitem>
+            <para>converts filesystems from "<option>appledouble = v2</option>"
+            to "<option>appledouble = ea</option>" on the fly when accessed
+            (can be disabled)</para>
+          </listitem>
+
+          <listitem>
+            <para><command><link linkend="dbd.1">dbd</link></command> can be
+            used to do conversion in one shot</para>
+          </listitem>
+        </itemizedlist></para>
+
+      <para>Implementation details:<itemizedlist>
+          <listitem>
+            <para>stores Mac Metadata (eg FinderInfo, AFP Flags, Comment,
+            CNID) in an Extended Attributed named
+            “<filename>org.netatalk.Metadata</filename>”</para>
+          </listitem>
+
+          <listitem>
+            <para>stores Mac ResourceFork either in<itemizedlist>
+                <listitem>
+                  <para>an Extended Attribute named
+                  “<filename>org.netatalk.ResourceFork</filename>”
+                  on Solaris (FreeBSD?) w. ZFS, or in</para>
+                </listitem>
+
+                <listitem>
+                  <para>an extra AppleDouble file named “<filename>._file</filename>” for a file
+                  named “<filename>file</filename>”</para>
+                </listitem>
+              </itemizedlist></para>
+          </listitem>
+
+          <listitem>
+            <para>the format of the ._ file is exactly as the Mac’s CIFS
+            client expects it when accessing the same filesystem via a CIFS
+            server (Samba), thus you can have parallel access from Macs to the
+            same dataset via AFP and CIFS without the risk of loosing data
+            (resources or metadata). Accessing the same dataset with CIFS
+            from Windows clients will still break the coupling of
+            “<filename>file</filename>” and “<filename>._file</filename>”
+            on non ZFS filesystems (see above), so for this we still
+            need an enhanced Samba VFS module (in the works).</para>
+          </listitem>
+        </itemizedlist></para>
+
+      <para>As these days the only applications making use of Resource Forks
+      are Adobe Photoshop (image preview) and Postscript Type 1 fonts, even on
+      eg Linux you’ll get rid of 99% of any extra Netatalk AppleDouble files
+      (and folders).</para>
+    </sect2>
+
+    <sect2>
+      <title>Other major changes</title>
+
+      <para><itemizedlist>
+          <listitem>
+            <para>New service controller daemon <link
+            linkend="netatalk.8">netatalk</link> which is responsible for
+            starting and restarting the AFP and CNID daemons. All bundled
+            start scripts have been updated, make sure to update yours!</para>
+          </listitem>
+
+          <listitem>
+            <para>The CNID databases are now stored under
+              <filename>/var/netatalk/CNID/</filename>
+              by default. You can use configure --localstatedir=PATH at
+              compile time to change the location.</para>
+          </listitem>
+
+          <listitem>
+            <para>Netatalk 2.x volume options “usedots” and “upriv” now
+            enabled by default</para>
+          </listitem>
+
+          <listitem>
+            <para>Removed SLP and AFP proxy support</para>
+          </listitem>
+
+          <listitem>
+            <para>Removed type/creator extension mapping
+            support</para>
+          </listitem>
+        </itemizedlist></para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Upgrading</title>
+
+    <para><orderedlist>
+        <listitem>
+          <para>Stop Netatalk 2.x</para>
+        </listitem>
+
+        <listitem>
+          <para>Install Netatalk 3</para>
+        </listitem>
+
+        <listitem>
+          <para>Manually recreate configuration in
+          <option>afp.conf</option> and <option>extmap.conf</option></para>
+        </listitem>
+
+        <listitem>
+          <para>Update your Netatalk start script (SMF, systemd, whatever...)
+          to only start <link linkend="netatalk.8">netatalk</link></para>
+        </listitem>
+
+        <listitem>
+          <para>Move <filename>afp_voluuid.conf</filename> and
+          <filename>afp_signature.conf</filename> to the localstate directory (default
+          <filename>/var/netatalk/</filename>), you can use <command>afpd -v</command>
+          in order to find the correct path</para>
+        </listitem>
+
+        <listitem>
+          <para>Start Netatalk 3</para>
+        </listitem>
+      </orderedlist></para>
+  </sect1>
+
+  <sect1>
+    <title>Notes</title>
+
+    <itemizedlist>
+      <listitem>
+        <para>Solaris ZFS permissions</para>
+
+        <para>On Solaris with ZFS you have to make sure users have
+        filesystem permissions to read, create, modify (default: yes) and
+        delete (default: no) extended attributes.</para>
+
+        <para>To grant this right to a group “staff” you’d use this
+        command:</para>
+
+        <para><command>pfexec chmod A+group:staff:RW:fd:allow
+        /Volumes/test/</command></para>
+
+        <para>Remember to run this once before you share a volume so that
+        this permission inherits appropiately (fd flags in above
+        command).</para>
+      </listitem>
+    </itemizedlist>
+  </sect1>
+  <sect1>
+    <title>Table with old and new configuration file names</title>
+    <para><table frame="all">
+        <title>old and new configuration file names</title>
+        <tgroup cols="3">
+          <colspec colname="c1" colnum="1" colwidth="1.0*"/>
+          <colspec colname="c2" colnum="2" colwidth="1.0*"/>
+          <colspec colname="c3" colnum="3" colwidth="1.0*"/>
+          <thead>
+            <row>
+              <entry>Old File Name</entry>
+              <entry>New File Name</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>-</entry>
+              <entry><filename>etc/afp.conf</filename></entry>
+              <entry>new ini-style format</entry>
+            </row>
+            <row>
+              <entry>-</entry>
+              <entry><filename>etc/extmap.conf</filename></entry>
+              <entry>starting with netatalk 3.0.2</entry>
+            </row>
+            <row>
+              <entry><filename>etc/netatalk/afp_signature.conf</filename></entry>
+              <entry><filename>var/netatalk/afp_signature.conf</filename></entry>
+              <entry>moved to $localstatedir</entry>
+            </row>
+            <row>
+              <entry><filename>etc/netatalk/afp_voluuid.conf</filename></entry>
+              <entry><filename>var/netatalk/afp_voluuid.conf</filename></entry>
+              <entry>moved to $localstatedir</entry>
+            </row>
+            <row>
+              <entry><filename>etc/netatalk/netatalk.conf</filename>
+              (<filename>/etc/default/netatalk</filename>)</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry><filename>etc/netatalk/afpd.conf</filename></entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry><filename>etc/netatalk/afp_ldap.conf</filename></entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry><filename>etc/netatalk/AppleVolumes.default</filename></entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry><filename>etc/netatalk/AppleVolumes.system</filename></entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry><filename>~/.AppleVolumes</filename></entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table></para>
+  </sect1>
+
+  <sect1>
+    <title>Table with old and new option names</title>
+    <para><table frame="all">
+        <title>from netatalk.conf (/etc/default/netatalk) to afp.conf</title>
+        <tgroup cols="6">
+          <colspec colname="c1" colnum="1" colwidth="1.0*"/>
+          <colspec colname="c2" colnum="2" colwidth="1.0*"/>
+          <colspec colname="c3" colnum="3" colwidth="1.0*"/>
+          <colspec colname="c4" colnum="4" colwidth="1.0*"/>
+          <colspec colname="c5" colnum="5" colwidth="1.0*"/>
+          <colspec colname="c6" colnum="6" colwidth="1.0*"/>
+          <thead>
+            <row>
+              <entry>Old netatalk.conf</entry>
+              <entry>New afp.conf</entry>
+              <entry>Old Default Value</entry>
+              <entry>New Default Value</entry>
+              <entry>Section</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>ATALK_NAME</entry>
+              <entry>hostname</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>use gethostname() by default</entry>
+            </row>
+            <row>
+              <entry>ATALK_UNIX_CHARSET</entry>
+              <entry>unix charset</entry>
+              <entry><emphasis role="bold">LOCALE</emphasis></entry>
+              <entry><emphasis role="bold">UTF8</emphasis></entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ATALK_MAC_CHARSET</entry>
+              <entry>mac charset</entry>
+              <entry>MAC_ROMAN</entry>
+              <entry>MAC_ROMAN</entry>
+              <entry>(G)/(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>CNID_METAD_RUN</entry>
+              <entry>-</entry>
+              <entry>yes</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>controlled by netatalk(8)</entry>
+            </row>
+            <row>
+              <entry>AFPD_RUN</entry>
+              <entry>-</entry>
+              <entry>yes</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>controlled by netatalk(8)</entry>
+            </row>
+            <row>
+              <entry>AFPD_MAX_CLIENTS</entry>
+              <entry>max connections</entry>
+              <entry><emphasis role="bold">20</emphasis></entry>
+              <entry><emphasis role="bold">200</emphasis></entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>AFPD_UAMLIST</entry>
+              <entry>uam list</entry>
+              <entry>-U uams_dhx.so,uams_dhx2.so</entry>
+              <entry>uams_dhx.so uams_dhx2.so</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>AFPD_GUEST</entry>
+              <entry>guest account</entry>
+              <entry>nobody</entry>
+              <entry>nobody</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>CNID_CONFIG</entry>
+              <entry>log level</entry>
+              <entry>-l log_note</entry>
+              <entry>cnid:note</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>CNID_CONFIG</entry>
+              <entry>log file</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ATALKD_RUN</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>PAPD_RUN</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>TIMELORD_RUN</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>A2BOOT_RUN</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>ATALK_BGROUND</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>ATALK_ZONE</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table><table frame="all">
+        <title>from afpd.conf to afp.conf</title>
+        <tgroup cols="6">
+          <colspec colname="c1" colnum="1" colwidth="1.0*"/>
+          <colspec colname="c2" colnum="2" colwidth="1.0*"/>
+          <colspec colname="c3" colnum="3" colwidth="1.0*"/>
+          <colspec colname="c4" colnum="4" colwidth="1.0*"/>
+          <colspec colname="c5" colnum="5" colwidth="1.0*"/>
+          <colspec colname="c6" colnum="6" colwidth="1.0*"/>
+          <thead>
+            <row>
+              <entry>Old afpd.conf</entry>
+              <entry>New afp.conf</entry>
+              <entry>Old Default Value</entry>
+              <entry>New Default Value</entry>
+              <entry>Section</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>1st field ("-" or "server name")</entry>
+              <entry>hostname</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>use gethostname() by default</entry>
+            </row>
+            <row>
+              <entry>-uamlist</entry>
+              <entry>uam list</entry>
+              <entry>-U uams_dhx.so,uams_dhx2.so</entry>
+              <entry>uams_dhx.so uams_dhx2.so</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-nozeroconf</entry>
+              <entry>zeroconf</entry>
+              <entry>-</entry>
+              <entry>yes (if supported)</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-advertise_ssh</entry>
+              <entry>advertise ssh</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-[no]savepassword</entry>
+              <entry>save password</entry>
+              <entry>-savepassword</entry>
+              <entry>yes</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-[no]setpassword</entry>
+              <entry>set password</entry>
+              <entry>-nosetpassword</entry>
+              <entry>no</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-client_polling</entry>
+              <entry>client polling</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-hostname</entry>
+              <entry>hostname</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>use gethostname() by default</entry>
+            </row>
+            <row>
+              <entry>-loginmesg</entry>
+              <entry>login message</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)/(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-guestname</entry>
+              <entry>guest account</entry>
+              <entry>nobody</entry>
+              <entry>nobody</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-passwdfile</entry>
+              <entry>passwd file</entry>
+              <entry>afppasswd</entry>
+              <entry>afppasswd</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-passwdminlen</entry>
+              <entry>passwd minlen</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-tickleval</entry>
+              <entry>tickleval</entry>
+              <entry>30</entry>
+              <entry>30</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-timeout</entry>
+              <entry>timeout</entry>
+              <entry>4</entry>
+              <entry>4</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-sleep</entry>
+              <entry>sleep time</entry>
+              <entry>10</entry>
+              <entry>10</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-dsireadbuf</entry>
+              <entry>dsireadbuf</entry>
+              <entry>12</entry>
+              <entry>12</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-server_quantum</entry>
+              <entry>server quantum</entry>
+              <entry>303840</entry>
+              <entry>303840</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-volnamelen</entry>
+              <entry>volnamelen</entry>
+              <entry>80</entry>
+              <entry>80</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-setuplog</entry>
+              <entry>log level</entry>
+              <entry>default log_note</entry>
+              <entry>default:note</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-setuplog</entry>
+              <entry>log file</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-admingroup</entry>
+              <entry>admingroup</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-k5service</entry>
+              <entry>k5 service</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-k5realm</entry>
+              <entry>k5 realm</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-k5keytab</entry>
+              <entry>k5 keytab</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-uampath</entry>
+              <entry>uam path</entry>
+              <entry><emphasis role="bold">etc/netatalk/uams/</emphasis></entry>
+              <entry><emphasis role="bold">lib/netatalk/</emphasis></entry>
+              <entry>(G)</entry>
+              <entry>moved to $libdir</entry>
+            </row>
+            <row>
+              <entry>-ipaddr</entry>
+              <entry>afp listen</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-cnidserver</entry>
+              <entry>cnid server</entry>
+              <entry>localhost:4700</entry>
+              <entry>localhost:4700</entry>
+              <entry>(G)/(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-port</entry>
+              <entry>port</entry>
+              <entry>548</entry>
+              <entry>548</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-signature</entry>
+              <entry>signature</entry>
+              <entry>auto</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-fqdn</entry>
+              <entry>fqdn</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-unixcodepage</entry>
+              <entry>unix charset</entry>
+              <entry><emphasis role="bold">LOCALE</emphasis></entry>
+              <entry><emphasis role="bold">UTF8</emphasis></entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-maccodepage</entry>
+              <entry>mac charset</entry>
+              <entry>MAC_ROMAN</entry>
+              <entry>MAC_ROMAN</entry>
+              <entry>(G)/(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-closevol</entry>
+              <entry>close vol</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-ntdomain</entry>
+              <entry>nt domain</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-ntseparator</entry>
+              <entry>nt separator</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-dircachesize</entry>
+              <entry>dircachesize</entry>
+              <entry>8192</entry>
+              <entry>8192</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-tcpsndbuf</entry>
+              <entry>tcpsndbuf</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>OS default</entry>
+            </row>
+            <row>
+              <entry>-tcprcvbuf</entry>
+              <entry>tcprcvbuf</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>OS default</entry>
+            </row>
+            <row>
+              <entry>-fcelistener</entry>
+              <entry>fce listener</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-fcecoalesce</entry>
+              <entry>fce coalesce</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-fceevents</entry>
+              <entry>fce events</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-fceholdfmod</entry>
+              <entry>fce holdfmod</entry>
+              <entry>60</entry>
+              <entry>60</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-mimicmodel</entry>
+              <entry>mimic model</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-adminauthuser</entry>
+              <entry>admin auth user</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-noacl2maccess</entry>
+              <entry>map acls</entry>
+              <entry>-</entry>
+              <entry>yes</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>-[no]tcp</entry>
+              <entry>-</entry>
+              <entry>-tcp</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>always TCP only</entry>
+            </row>
+            <row>
+              <entry>-[no]ddp</entry>
+              <entry>-</entry>
+              <entry>-noddp</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>-[no]transall</entry>
+              <entry>-</entry>
+              <entry>-tcp -noddp</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>always TCP only</entry>
+            </row>
+            <row>
+              <entry>-nodebug</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>-[no]slp</entry>
+              <entry>-</entry>
+              <entry>-noslp</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>SLP support is obsoleted</entry>
+            </row>
+            <row>
+              <entry>-[no]uservolfirst</entry>
+              <entry>-</entry>
+              <entry>-nouservolfirst</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>uservol is obsoleted</entry>
+            </row>
+            <row>
+              <entry>-[no]uservol</entry>
+              <entry>-</entry>
+              <entry>-uservol</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>uservol is obsoleted</entry>
+            </row>
+            <row>
+              <entry>-proxy</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>-defaultvol</entry>
+              <entry>-</entry>
+              <entry>AppleVolumes.default</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>afp.conf only</entry>
+            </row>
+            <row>
+              <entry>-systemvol</entry>
+              <entry>-</entry>
+              <entry>AppleVolumes.system</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>afp.conf only</entry>
+            </row>
+            <row>
+              <entry>-loginmaxfail</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>not supported from the biginning</entry>
+            </row>
+            <row>
+              <entry>-unsetuplog</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>-authprintdir</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>-ddpaddr</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>AppleTalk is obsoleted</entry>
+            </row>
+            <row>
+              <entry>-[no]icon</entry>
+              <entry>-</entry>
+              <entry>-noicon</entry>
+              <entry></entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>-keepsessions</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete. Use kill -HUP.</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table><table frame="all">
+        <title>from afp_ldap.conf to afp.conf</title>
+        <tgroup cols="6">
+          <colspec colname="c1" colnum="1" colwidth="1.0*"/>
+          <colspec colname="c2" colnum="2" colwidth="1.0*"/>
+          <colspec colname="c3" colnum="3" colwidth="1.0*"/>
+          <colspec colname="c4" colnum="4" colwidth="1.0*"/>
+          <colspec colname="c5" colnum="5" colwidth="1.0*"/>
+          <colspec colname="c6" colnum="6" colwidth="1.0*"/>
+          <thead>
+            <row>
+              <entry>Old afp_ldap.conf</entry>
+              <entry>New afp.conf</entry>
+              <entry>Old Default Value</entry>
+              <entry>New Defalut Value</entry>
+              <entry>Section</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>ldap_server</entry>
+              <entry>ldap server</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_auth_method</entry>
+              <entry>ldap auth method</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_auth_dn</entry>
+              <entry>ldap auth dn</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_auth_pw</entry>
+              <entry>ldap auth pw</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_userbase</entry>
+              <entry>ldap userbase</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_userscope</entry>
+              <entry>ldap userscope</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_groupbase</entry>
+              <entry>ldap groupbase</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_groupscope</entry>
+              <entry>ldap groupscope</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_uuid_attr</entry>
+              <entry>ldap uuid attr</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_uuid_string</entry>
+              <entry>ldap uuid string</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ldap_name_attr</entry>
+              <entry>ldap name attr</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry> ldap_group_attr</entry>
+              <entry>ldap group attr</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(G)</entry>
+              <entry>-</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table><table frame="all">
+        <title>from AppleVolumes.* to afp.conf</title>
+        <tgroup cols="6">
+          <colspec colname="c1" colnum="1" colwidth="1.0*"/>
+          <colspec colname="c2" colnum="2" colwidth="1.0*"/>
+          <colspec colname="c3" colnum="3" colwidth="1.0*"/>
+          <colspec colname="c4" colnum="4" colwidth="1.0*"/>
+          <colspec colname="c5" colnum="5" colwidth="1.0*"/>
+          <colspec colname="c6" colnum="6" colwidth="1.0*"/>
+          <thead>
+            <row>
+              <entry>Old AppleVolumes.*</entry>
+              <entry>New afp.conf</entry>
+              <entry>Old Default Value</entry>
+              <entry>New Defalut Value</entry>
+              <entry>Section</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>(leading-dot lines)</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>move to extmap.conf</entry>
+            </row>
+            <row>
+              <entry>:DEFAULT:</entry>
+              <entry>-</entry>
+              <entry>options:upriv,usedots</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>use "vol preset ="</entry>
+            </row>
+            <row>
+              <entry>1st field ("~")</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>use [Homes] section</entry>
+            </row>
+            <row>
+              <entry>1st field ("/path")</entry>
+              <entry>path</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>2nd field</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>use section name</entry>
+            </row>
+            <row>
+              <entry>allow:</entry>
+              <entry>valid users</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>deny:</entry>
+              <entry>invalid users</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>rwlist:</entry>
+              <entry>rwlist</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>rolist:</entry>
+              <entry>rolist</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>volcharset:</entry>
+              <entry>vol charset</entry>
+              <entry><emphasis role="bold">UTF8</emphasis></entry>
+              <entry><emphasis role="bold">(same as unix charset)</emphasis></entry>
+              <entry>(G)/(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>maccharset:</entry>
+              <entry>mac charset</entry>
+              <entry>MAC_ROMAN</entry>
+              <entry>MAC_ROMAN</entry>
+              <entry>(G)/(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>veto:</entry>
+              <entry>veto files</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>cnidscheme:</entry>
+              <entry>cnid scheme</entry>
+              <entry>dbd</entry>
+              <entry>dbd</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>casefold:</entry>
+              <entry>casefold</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>adouble:</entry>
+              <entry>appledouble</entry>
+              <entry><emphasis role="bold">v2</emphasis></entry>
+              <entry><emphasis role="bold">ea</emphasis></entry>
+              <entry>(V)</entry>
+              <entry>v1, osx and sfm are obsoleted</entry>
+            </row>
+            <row>
+              <entry>cnidserver:</entry>
+              <entry>cnid server</entry>
+              <entry>localhost:4700</entry>
+              <entry>localhost:4700</entry>
+              <entry>(G)/(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>dbpath:</entry>
+              <entry>vol dbpath</entry>
+              <entry><emphasis role="bold">(volume directory)</emphasis></entry>
+              <entry><emphasis role="bold">var/netatalk/CNID/</emphasis></entry>
+              <entry>(G)</entry>
+              <entry>moved to $localstatedir</entry>
+            </row>
+            <row>
+              <entry>umask:</entry>
+              <entry>umask</entry>
+              <entry>0000</entry>
+              <entry>0000</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>dperm:</entry>
+              <entry>directory perm</entry>
+              <entry>0000</entry>
+              <entry>0000</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>fperm:</entry>
+              <entry>file perm</entry>
+              <entry>0000</entry>
+              <entry>0000</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>password:</entry>
+              <entry>password</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>root_preexec:</entry>
+              <entry>root preexec</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>preexec:</entry>
+              <entry>preexec</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>root_postexec:</entry>
+              <entry>root postexec</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>postexec:</entry>
+              <entry>postexec</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>allowed_hosts:</entry>
+              <entry>hosts allow</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>denied_hosts:</entry>
+              <entry>hosts deny</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>ea:</entry>
+              <entry>ea</entry>
+              <entry>auto</entry>
+              <entry>auto</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>volsizelimit:</entry>
+              <entry>vol size limit</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>perm:</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>Use "directory perm" and "file perm"</entry>
+            </row>
+            <row>
+              <entry>forceuid:</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>forcegid:</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:ro</entry>
+              <entry>read only</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:invisibledots</entry>
+              <entry>invisible dots</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:nostat</entry>
+              <entry>stat vol</entry>
+              <entry>-</entry>
+              <entry>yes</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:preexec_close</entry>
+              <entry>preexec close</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:root_preexec_close</entry>
+              <entry>root preexec close</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:upriv</entry>
+              <entry>unix priv</entry>
+              <entry>-</entry>
+              <entry><emphasis role="bold">yes</emphasis></entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:nodev</entry>
+              <entry>cnid dev</entry>
+              <entry>-</entry>
+              <entry>yes</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:illegalseq</entry>
+              <entry>illegal seq</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:tm</entry>
+              <entry>time machine</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:searchdb</entry>
+              <entry>search db</entry>
+              <entry>-</entry>
+              <entry>no</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:nonetids</entry>
+              <entry>network ids</entry>
+              <entry>-</entry>
+              <entry>yes</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:noacls</entry>
+              <entry>acls</entry>
+              <entry>-</entry>
+              <entry>yes</entry>
+              <entry>(V)</entry>
+              <entry>-</entry>
+            </row>
+            <row>
+              <entry>options:nohex</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>auto-convert from ":2f" to ":"</entry>
+            </row>
+            <row>
+              <entry>options:usedots</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>auto-convert from ":2e" to "."</entry>
+            </row>
+            <row>
+              <entry>options:nofileid</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:prodos</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:mswindows</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:crlf</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:noadouble</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:limitsize</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:dropbox</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:dropkludge</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:nocnidcache</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+            <row>
+              <entry>options:caseinsensitive</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>-</entry>
+              <entry>obsolete</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table></para>
+  </sect1>
+
+  <sect1>
+    <title>To Do</title>
+
+    <para><itemizedlist>
+        <listitem>
+          <para>test <command>ad</command> utils with <option>appledouble =
+          ea</option></para>
+        </listitem>
+      </itemizedlist></para>
+  </sect1>
+</chapter>
diff --git a/doc/netatalk.html b/doc/netatalk.html
new file mode 100644 (file)
index 0000000..b0b7904
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+    <div id="header">
+        <div id="logo"></div>
+        <div id="menlinks">
+          <a href="/" title="Return to Netatalk home">[main]</a>
+          <a href="http://netatalk.sourceforge.net/wiki/" title="Netatalk Wiki">[wiki]</a>
+          <a href="/3.0/htmldocs" title="Netatalk Manual">[documentation]</a>
+          <a href="http://sourceforge.net/project/showfiles.php?group_id=8642" title="Download Netatalk from sourceforge">[downloads]</a>
+          <a href="/support.php" title="Support">[support]</a>
+          <a href="/links.php" title="Netatalk related links">[links]</a>
+          <img src="/gfx/end.gif" alt="" width="125" height="7" />
+        </div>
+    </div>
+</html>
diff --git a/doc/www/ReleaseNotes b/doc/www/ReleaseNotes
new file mode 100644 (file)
index 0000000..ab0441a
--- /dev/null
@@ -0,0 +1,294 @@
+Netatalk 3.0.3
+==============
+
+The Netatalk development team is proud to announce version 3.0.3 of
+the Netatalk File Sharing suite. This is the latest update to the 3.0
+release series. All users are encouraged to upgrade their systems to 3.0.3.
+
+Netatalk is a freely-available Open Source AFP fileserver.
+A *NIX/*BSD system running Netatalk is capable of serving many Macintosh
+clients simultaneously as an AppleShare file server (AFP).
+
+The suite contains:
+
+* netatalk   - the main server service controller
+* afpd       - the AFP file server daemin
+* cnid_metad - the CNID database multiplexing daemon
+* cnid_dbd   - the CNID database daemon serving CNIDs for AFP volumes
+* various supporting programs and utilities
+
+Summary of major new features and enhancements in 3.0
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* New ini style configuration file afp.conf which replaces all previous
+  configuration files
+* New default AppleDouble backend using filesystem Extended Attributes,
+  conversion from AppleDouble v2 is done automatically on access
+* New service controller process "netatalk" responsible for starting and
+  restarting afpd and cnid_metad as necessary
+* AppleTalk support has been removed
+* Coherent cross-platform locking with Solaris CIFS server
+
+Please make sure to read the upgrading section in the Netatalk online
+manual before trying to upgrade your system to 3.0!
+
+  http://netatalk.sourceforge.net/3.0/htmldocs/upgrade.html
+
+License
+~~~~~~~
+
+Netatalk is a Free/Open Source Software project and is released under
+the GNU General Public License (GPLv2).  The full license text is available
+at:
+
+  http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+Changes in 3.0.3
+~~~~~~~~~~~~~~~~
+* UPD: afpd: Increase default DSI server quantum to 1 MB
+* UPD: bundled libevent2 is now static
+* NEW: --with-lockfile=PATH configure option for specifying an
+       alternative path for the netatalk lockfile.
+* UPD: systemd service file use PIDFile and ExecReload.
+       From FR #70.
+* UPD: RedHat sysvinit: rm graceful, reimplement reload, add condrestart
+* FIX: Couldn't create folders on FreeBSD 9.1 ZFS fileystems.
+       Fixed bug #491.
+* FIX: Fix an issue with user homes when user home directory has not the
+       same name as the username.
+       Fixes bug #497.
+* UPD: Fix PAM config install, new default installation dir is
+       $sysconfdir/pam.d/. Add configure option --with-pam-confdir
+       to specify alternative path.
+* NEW: AFP stats about active session via dbus IPC. Client side python
+       program `afpstats`. Requires dbus, dbus-glib any python-dbus.
+       configure option --dbus-sysconf-dir for specifying dbus
+       system security configuration files.
+       New option 'afpstats' (default: no) which determines whether
+       to enable the feature or not.
+* NEW: configure option --with-init-dir
+* NEW: dtrace probes, cf include/atalk/afp_dtrace.d for available
+       probes.
+* UPD: Reload groups when reloading volumes. FR #71.
+* FIX: Attempt to read read-only ._ rfork results in disconnect.
+       Fixes bug #502.
+* FIX: File's ressource fork can't be read if metadata EA is missing.
+       Fixes bug #501.
+* FIX: Conversion from adouble v2 to ea for directories.
+       Fixes bug #500.
+* FIX: Error messages when mounting read-only filesystems.
+       Fixes bug #504.
+* FIX: Permissions of ._ AppleDouble ressource fork after conversion
+       from v2 to ea.
+       Fixes bug #505.
+* UPD: Use FreeBSD sendfile() capability to send protocol header.
+       From FR #75.
+* UPD: Increase IO size when sendfile() is not used.
+       From FR #76.
+* FIX: Can't set Finder label on symlinked folder with "follow symlinks = yes".
+       Fixes bug #508.
+* FIX: Setting POSIX ACLs on Linux
+       Fixes bug #506.
+* FIX: "ad ls" segfault if requested object is not in an AFP volume.
+       Fixes bug #496.
+
+Changes in 3.0.2
+~~~~~~~~~~~~~~~~
+* NEW: afpd: Put file extension type/creator mapping back in which had
+       been removed in 3.0.
+* NEW: afpd: new option 'ad domain'. From FR #66.
+* FIX: volumes and home share with symlinks in the path
+* FIX: Copying packages to a Netatalk share could fail, bug #469
+* FIX: Reloading volumes from config file was broken.  Fixes bug #474.
+* FIX: Fix _device-info service type registered with dns-sd API
+* FIX: Fix pathname bug for FCE modified event.
+* FIX: Remove length limitation of options like "valid users".
+       Fixes bug #473.
+* FIX: Dont copy our metadata EA in copyfile(). Fixes bug #452.
+* FIX: Fix an error where catalog search gave incomplete results.
+       Fixes bug #479.
+* REM: Remove TimeMachine volume used size FCE event.
+* UPD: Add quoting support to '[in]valid users' option. Fixes bug #472.
+* FIX: Install working PAM config on Solaris 11. Fixes bug #481.
+* FIX: Fix a race condition between dbd and the cnid_dbd daemon
+       which could result in users being disconnected from volumes
+       when dbd was scanning their volumes. Fixes bug #477.
+* FIX: Netatalk didn't start when the last line of the config file
+       afp.conf wasn't terminated by a newline. Fixes bug #476.
+* NEW: Add a new volumes option 'follow symlinks'. The default setting is
+       false, symlinks are not followed on the server. This is the same
+       behaviour as OS X's AFP server.
+       Setting the option to true causes afpd to follow symlinks on the
+       server. symlinks may point outside of the AFP volume, currently
+       afpd doesn't do any checks for "wide symlinks".
+* FIX: Automatic AppleDouble conversion to EAs failing for directories.
+       Fixes bug #486.
+* FIX: dbd failed to convert appledouble files of symlinks.
+       Fixes bug #490.
+
+Changes in 3.0.1
+~~~~~~~~~~~~~~~~
+* NEW: afpd: Optional "ldap uuid encoding = string | ms-guid" parameter to
+       afp.conf, allowing for usage of the binary objectGUID fields from
+       Active Directory.
+* FIX: afpd: Fix a Solaris 10 SPARC sendfilev bug
+* FIX: afpd: Fix a crash on FreeBSD
+* FIX: afpd: Fixes open file handle refcounting bug which was reported as
+       being unable to play movies off a Netatalk AFP share.
+       Bug ID 3559783.
+* FIX: afpd: Fix a possible data corruption when reading from and writing
+       to the server simultaniously under load
+* FIX: Fix possible alignment violations due to bad casts
+* FIX: dbd: Fix logging
+* FIX: apple_dump: Extended Attributes AppleDouble support for *BSD
+* FIX: handling of '/' and ':' in volume name
+* UPD: Install relevant includes necessary for building programs with
+       installed headers and shared lib libatalk
+* UPD: libevent configure args to pick up installed version. Removed
+       configure arg --disable-libevent, added configure args
+       --with-libevent-header|lib.
+* UPD: gentoo initscript: merge from portage netatalk.init,v 1.1
+* REM: Remove --with-smbsharemodes configure option, it was an
+       empty stub not yet implemented
+
+Changes in 3.0
+~~~~~~~~~~~~~~
+
+* UPD: afpd: force read only mode if cnid scheme is last
+* REM: afpd: removed global option "icon"
+* FIX: CNID path for user homes
+
+Changes in 3.0 beta2
+~~~~~~~~~~~~~~~~~~~~
+
+* UPD: Solaris and friends: Replace initscript with SMF manifest
+* FIX: Solaris and friends: resource fork handling
+
+Changes in 3.0 beta1
+~~~~~~~~~~~~~~~~~~~~
+
+* UPD: afpd: Performance tuning of read/write AFP operations. New option
+       "afp read locks" (default: no) which disables that the server
+       applies UNIX byte range locks to regions of files in AFP read and
+       write calls.
+* UPD: apple_dump: Extended Attributes AppleDouble support.
+       (*BSD is not supported yet)
+
+Changes in 3.0 alpha3
+~~~~~~~~~~~~~~~~~~~~~
+
+* NEW: afpd: Per volume "login message", NetAFP bug ID #18
+* NEW: afpd: Cross-platform locking (share modes) on Solaris and derivates
+       with Solaris CIFS/SMB server. Uses new Solaris fcntl F_SHARE share
+       reservation locking primitives. Enabled by default, set global
+       "solaris share reservations" option to false to disable it.
+* NEW: ad: ad set subcommand for changing Mac metadata on the server
+* UPD: unix charset is UTF8 by default
+       vol charset is same value as unix charset by default
+* UPD: .AppleDesktop/ are stored in $localstatedir/netatalk/CNID
+       (default: /var/netatalk/CNID), databases found in AFP volumes are
+       automatically moved
+* FIX: afpd: Server info packet was malformed resulting in broken
+       server names being displayed on clients
+* FIX: afpd: Byte order detection. Fixes an error where Netatalk on
+       OpenIndiana returned wrong volume size information.
+
+Changes in 3.0 alpha2
+~~~~~~~~~~~~~~~~~~~~~
+
+* UPD: afpd: Store '.' as is and '/' as ':' on the server, don't
+       CAP hexencode as "2e" and "2f" respectively
+* UPD: afdp: Automatic name conversion, renaming files and directories
+       containing CAP sequences to their not enscaped forms
+* UPD: afpd: Correct handling of user homes and users without homes
+* UPD: afpd: Perform complete automatic adouble:v2 to adouble:ea conversion
+       as root. Previously only unlinking the adouble:v2 file was done as root
+* UPD: dbd: -C option removes CAP encoding
+* UPD: Add graceful option to RedHat init script
+* UPD: Add --disable-bundled-libevent configure options When set to yes,
+       we rely on a properly installed version on libevent CPPFLAGS and LDFLAGS
+       should be set properly to pick that up
+* UPD: Run ldconfig on Linux at the end of make install
+* FIX: afpd: ad cp on appledouble = ea volumes
+* FIX: dbd: ignore ._ appledouble files
+* REM: Volumes options "use dots" and "hex encoding"
+
+Changes in 3.0 alpha1
+~~~~~~~~~~~~~~~~~~~~~
+
+* NEW: Central configuration file afp.conf which replaces all previous files
+* NEW: netatalk: service controller starting and restarting afpd and cnid_metad
+       as necessary
+* NEW: afpd: Extended Attributes AppleDouble backend (default)
+* UPD: CNID databases are stored in $localstatedir/netatalk/CNID
+       (default: /var/netatalk/CNID), databases found in AFP volumes are
+       automatically moved
+* UPD: Start scripts and service manifests have been changed to only start
+       the new netatalk service controller process
+* UPD: afpd: UNIX privileges and use dots enabled by default
+* UPD: afpd: Support for arbitrary AFP volumes using variable expansion has been
+       removed
+* UPD: afpd: afp_voluuid.conf and afp_signature.conf location has been
+       changed to $localstatedir/netatalk/ (default: /var/netatalk/)
+* UPD: afpd: default server messages dir changed to $localstatedir/netatalk/msg/
+* UPD: dbd: new option -C for conversion from AppleDouble v2 to ea
+* REM: AppleTalk support has been removed
+* REM: afpd: SLP and AFP proxy support have been removed
+* REM: afpd: legacy file extension to type/creator mapping has been removed
+* REM: afpd: AppleDouble backends v1, osx and sfm have been removed
+
+
+Supported Platforms
+~~~~~~~~~~~~~~~~~~~
+
+As of Netatalk 3.0 the following operating systems are supported:
+
+ * FreeBSD
+ * Linux
+ * OpenBSD
+ * NetBSD
+ * Solaris and derivates
+
+Netatalk may compile and run on other operating systems as well, but
+it is not well-tested on those.  We welcome patches and suggestions
+for enhancing the portability of Netatalk as well as success and failure
+stories.  Please write to netatalk-devel@lists.sourceforge.net.
+
+Availability
+~~~~~~~~~~~~
+
+Netatalk tar-balls can be found at:
+
+http://sourceforge.net/project/showfiles.php?group_id=8642
+
+Netatalk is also available via anonymous git.  See the SourceForge project
+site for anonymous git instructions. 
+
+Contact
+~~~~~~~
+
+For more information about Netatalk, see its web page at:
+
+http://netatalk.sourceforge.net/
+
+The project is hosted at SourceForge.  The SourceForge project page is
+located at:
+
+http://sourceforge.net/projects/netatalk/
+
+The Netatalk development team can be reached via the mailing list
+netatalk-devel@lists.sourceforge.net.  For subscription information and
+archives see Netatalk's SourceForge project page.
+
+netatalk-admins@lists.sourceforge.net is a mailing list for Netatalk
+system administrators.  For subscription information and archives see
+the Netatalk web page.
+
+Acknowledgements
+~~~~~~~~~~~~~~~~
+
+We would like to thank all contributors to the Netatalk project for
+their commitment.  Without the many suggestions, bug and problem reports,
+patches, and reviews this project wouldn't be where it is.
+
+ - The Netatalk Development Team, January 2013
diff --git a/doc/www/asciidoc.conf b/doc/www/asciidoc.conf
new file mode 100644 (file)
index 0000000..85b3df4
--- /dev/null
@@ -0,0 +1,610 @@
+#
+# asciidoc.conf
+#
+# Asciidoc global configuration file.
+# Contains backend independent configuration settings that are applied to all
+# AsciiDoc documents.
+#
+
+[miscellaneous]
+tabsize=8
+textwidth=70
+newline=\r\n
+
+[attributes]
+backend-alias-html=xhtml11
+backend-alias-docbook=docbook45
+toclevels=2
+sectids=
+iconsdir=./images/icons
+encoding=UTF-8
+# Uncomment to use xhtml11 quirks mode CSS.
+#quirks=
+# Uncomment to use the Pygments source highlighter instead of GNU highlighter.
+#pygments=
+# Uncomment to use deprecated quote attributes.
+#deprecated-quotes=
+empty=
+# Attribute and AttributeList element patterns.
+attributeentry-pattern=^:(?P<attrname>\w[^.]*?)(\.(?P<attrname2>.*?))?:(\s+(?P<attrvalue>.*))?$
+attributelist-pattern=(?u)(^\[\[(?P<id>[\w_:][\w_:.-]*)(,(?P<reftext>.*?))?\]\]$)|(^\[(?P<attrlist>.*)\]$)
+# Substitution attributes for escaping AsciiDoc processing.
+amp=&
+lt=<
+gt=>
+brvbar=|
+nbsp=&#160;
+zwsp=&#8203;
+wj=&#8288;
+deg=&#176;
+backslash=\
+two-colons=::
+two-semicolons=;;
+# DEPRECATED: underscore attribute names.
+two_colons=::
+two_semicolons=;;
+# Left and right single and double quote characters.
+# See http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks
+lsquo=&#8216;
+rsquo=&#8217;
+ldquo=&#8220;
+rdquo=&#8221;
+
+[titles]
+subs=specialcharacters,quotes,replacements,macros,attributes,replacements2
+# Double-line title pattern and underlines.
+sectiontitle=^(?P<title>.*?)$
+underlines="==","--","~~","^^","++"
+# Single-line title patterns.
+sect0=^= +(?P<title>[\S].*?)( +=)?$
+sect1=^== +(?P<title>[\S].*?)( +==)?$
+sect2=^=== +(?P<title>[\S].*?)( +===)?$
+sect3=^==== +(?P<title>[\S].*?)( +====)?$
+sect4=^===== +(?P<title>[\S].*?)( +=====)?$
+blocktitle=^\.(?P<title>([^.\s].*)|(\.[^.\s].*))$
+
+[specialcharacters]
+&=&amp;
+<=&lt;
+>=&gt;
+
+[quotes]
+# The order is important, quotes are processed in conf file order.
+**=#strong
+*=strong
+``|''=doublequoted
+'=emphasis
+`|'=singlequoted
+ifdef::no-inline-literal[]
+`=monospaced
+endif::no-inline-literal[]
+# +++ and $$ quoting is applied to the +++ and $$ inline passthrough
+# macros to allow quoted attributes to be used.
+# This trick only works with inline passthrough macros.
++++=#unquoted
+$$=#unquoted
+++=#monospaced
++=monospaced
+__=#emphasis
+_=emphasis
+\##=#unquoted
+\#=unquoted
+^=#superscript
+~=#subscript
+
+[specialwords]
+emphasizedwords=
+strongwords=
+monospacedwords=
+
+[replacements]
+# Replacements performed in order of configuration file entry.  The first entry
+# of each replacement pair performs the (non-escaped) replacement, the second
+# strips the backslash from the escaped replacement.
+
+# (C) Copyright (entity reference &copy;)
+(?<!\\)\(C\)=&#169;
+\\\(C\)=(C)
+
+# (R) registered trade mark (entity reference &reg;
+(?<!\\)\(R\)=&#174;
+\\\(R\)=(R)
+
+# (TM) Trademark (entity reference &trade;)
+(?<!\\)\(TM\)=&#8482;
+\\\(TM\)=(TM)
+
+# -- Spaced and unspaced em dashes (entity reference &mdash;).
+# Space on both sides is translated to thin space characters.
+(^-- )=&#8212;&#8201;
+(\n-- )|( -- )|( --\n)=&#8201;&#8212;&#8201;
+(\w)--(\w)=\1&#8212;\2
+\\--(?!-)=--
+
+# Replace vertical typewriter apostrophe with punctuation apostrophe.
+(\w)'(\w)=\1&#8217;\2
+(\w)\\'(\w)=\1'\2
+
+# ... Ellipsis (entity reference &hellip;)
+(?<!\\)\.\.\.=&#8230;
+\\\.\.\.=...
+
+# Arrows from the Arrows block of Unicode.
+# -> right arrow
+(?<!\\)-&gt;=&#8594;
+\\-&gt;=-&gt;
+# => right double arrow
+(?<!\\)\=&gt;=&#8658;
+\\\=&gt;==&gt;
+# <- left arrow
+(?<!\\)&lt;-=&#8592;
+\\&lt;-=&lt;-
+# <= left double arrow
+(?<!\\)&lt;\==&#8656;
+\\&lt;\==&lt;=
+
+# Arbitrary entity references.
+(?<!\\)&amp;([:_#a-zA-Z][:_.\-\w]*?;)=&\1
+\\(&amp;[:_#a-zA-Z][:_.\-\w]*?;)=\1
+
+#-----------
+# Paragraphs
+#-----------
+[paradef-default]
+delimiter=(?s)(?P<text>\S.*)
+posattrs=style
+style=normal
+template::[paragraph-styles]
+
+[paradef-literal]
+delimiter=(?s)(?P<text>\s+.*)
+options=listelement
+posattrs=style
+style=literal
+template::[paragraph-styles]
+
+[paradef-admonition]
+delimiter=(?s)^\s*(?P<style>NOTE|TIP|IMPORTANT|WARNING|CAUTION):\s+(?P<text>.+)
+template::[paragraph-styles]
+
+[paragraph-styles]
+normal-style=template="paragraph"
+verse-style=template="verseparagraph",posattrs=["style","attribution","citetitle"]
+quote-style=template="quoteparagraph",posattrs=["style","attribution","citetitle"]
+literal-style=template="literalparagraph",subs=["verbatim"]
+listing-style=template="listingparagraph",subs=["verbatim"]
+NOTE-style=template="admonitionparagraph",name="note",caption="{note-caption}"
+TIP-style=template="admonitionparagraph",name="tip",caption="{tip-caption}"
+IMPORTANT-style=template="admonitionparagraph",name="important",caption="{important-caption}"
+WARNING-style=template="admonitionparagraph",name="warning",caption="{warning-caption}"
+CAUTION-style=template="admonitionparagraph",name="caution",caption="{caution-caption}"
+
+[literalparagraph]
+template::[literalblock]
+
+[verseparagraph]
+template::[verseblock]
+
+[quoteparagraph]
+template::[quoteblock]
+
+[listingparagraph]
+template::[listingblock]
+
+[macros]
+#--------------
+# Inline macros
+#--------------
+# Backslash prefix required for escape processing.
+# (?s) re flag for line spanning.
+
+# Macros using default syntax.
+(?su)(?<!\w)[\\]?(?P<name>http|https|ftp|file|irc|mailto|callto|image|link|anchor|xref|indexterm):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+
+# These URL types don't require any special attribute list formatting.
+(?su)(?<!\S)[\\]?(?P<name>http|https|ftp|file|irc):(?P<target>//[^\s<>]*[\w/])=
+# Allow a leading parenthesis and square bracket.
+(?su)(?<\=[([])[\\]?(?P<name>http|https|ftp|file|irc):(?P<target>//[^\s<>]*[\w/])=
+# Allow <> brackets.
+(?su)[\\]?&lt;(?P<name>http|https|ftp|file|irc):(?P<target>//[^\s<>]*[\w/])&gt;=
+
+# Email addresses don't require special attribute list formatting.
+# The before ">: and after "< character exclusions stop multiple substitution.
+(?su)(?<![">:\w._/-])[\\]?(?P<target>\w[\w._-]*@[\w._-]*\w)(?!["<\w_-])=mailto
+
+# Allow footnote macros hard up against the preceding word so the footnote mark
+# can be placed against the noted text without an intervening space
+# (http://groups.google.com/group/asciidoc/browse_frm/thread/e1dcb7ee0efc17b5).
+(?su)[\\]?(?P<name>footnote|footnoteref):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+
+# Anchor: [[[id]]]. Bibliographic anchor.
+(?su)[\\]?\[\[\[(?P<attrlist>[\w_:][\w_:.-]*?)\]\]\]=anchor3
+# Anchor: [[id,xreflabel]]
+(?su)[\\]?\[\[(?P<attrlist>[\w"_:].*?)\]\]=anchor2
+# Link: <<id,text>>
+(?su)[\\]?&lt;&lt;(?P<attrlist>[\w"_:].*?)&gt;&gt;=xref2
+
+ifdef::asciidoc7compatible[]
+# Index term: ++primary,secondary,tertiary++
+(?su)(?<!\S)[\\]?\+\+(?P<attrlist>[^+].*?)\+\+(?!\+)=indexterm
+# Index term: +primary+
+# Follows ++...++ macro otherwise it will match them.
+(?<!\S)[\\]?\+(?P<attrlist>[^\s\+][^+].*?)\+(?!\+)=indexterm2
+endif::asciidoc7compatible[]
+
+ifndef::asciidoc7compatible[]
+# Index term: (((primary,secondary,tertiary)))
+(?su)(?<!\()[\\]?\(\(\((?P<attrlist>[^(].*?)\)\)\)(?!\))=indexterm
+# Index term: ((primary))
+# Follows (((...))) macro otherwise it will match them.
+(?<!\()[\\]?\(\((?P<attrlist>[^\s\(][^(].*?)\)\)(?!\))=indexterm2
+endif::asciidoc7compatible[]
+
+# Callout
+[\\]?&lt;(?P<index>\d+)&gt;=callout
+
+# Passthrough macros.
+(?su)[\\]?(?P<name>pass):(?P<subslist>\S*?)\[(?P<passtext>.*?)(?<!\\)\]=[]
+
+# Triple-plus and double-dollar inline passthroughs.
+(?su)[\\]?\+\+\+(?P<passtext>.*?)\+\+\+=pass[]
+(?su)[\\]?\$\$(?P<passtext>.*?)\$\$=pass[specialcharacters]
+
+# Inline literal.
+ifndef::no-inline-literal[]
+(?su)(?<![`\w])([\\]?`(?P<passtext>[^`\s]|[^`\s].*?\S)`)(?![`\w])=literal[specialcharacters]
+endif::no-inline-literal[]
+
+# Inline comment.
+(?mu)^[\\]?//(?P<passtext>[^/].*|)$=comment[specialcharacters]
+
+# Default (catchall) inline macro is not implemented so there is no ambiguity
+# with previous definition that could result in double substitution of escaped
+# references.
+#(?su)[\\]?(?P<name>\w(\w|-)*?):(?P<target>\S*?)\[(?P<passtext>.*?)(?<!\\)\]=
+
+#-------------
+# Block macros
+#-------------
+# Macros using default syntax.
+(?u)^(?P<name>image|unfloat)::(?P<target>\S*?)(\[(?P<attrlist>.*?)\])$=#
+
+# Passthrough macros.
+(?u)^(?P<name>pass)::(?P<subslist>\S*?)(\[(?P<passtext>.*?)\])$=#
+
+^'{3,}$=#ruler
+^<{3,}$=#pagebreak
+^//(?P<passtext>[^/].*|)$=#comment[specialcharacters]
+
+[unfloat-blockmacro]
+# Implemented in HTML backends.
+
+#-----------------
+# Delimited blocks
+#-----------------
+[blockdef-comment]
+delimiter=^/{4,}$
+options=skip
+
+[blockdef-sidebar]
+delimiter=^\*{4,}$
+template=sidebarblock
+options=sectionbody
+posattrs=style
+# DEPRECATED: Use Openblock instead.
+abstract-style=template="abstractblock"
+
+[blockdef-open]
+# A block without opening or closing tags.
+delimiter=^--$
+template=openblock
+options=sectionbody
+posattrs=style
+abstract-style=template="abstractblock"
+partintro-style=template="partintroblock"
+
+[blockdef-pass]
+delimiter=^\+{4,}$
+template=passblock
+# Default subs choosen for backward compatibility.
+subs=attributes,macros
+posattrs=style
+pass-style=template="passblock",subs=[]
+
+[blockdef-listing]
+delimiter=^-{4,}$
+template=listingblock
+subs=verbatim
+posattrs=style
+
+[blockdef-literal]
+delimiter=^\.{4,}$
+template=literalblock
+subs=verbatim
+posattrs=style
+listing-style=template="listingblock"
+# DEPRECATED: Use verse style on quote blocks instead.
+verse-style=template="verseblock",subs="normal"
+
+[blockdef-quote]
+delimiter=^_{4,}$
+subs=normal
+style=quote
+posattrs=style,attribution,citetitle
+quote-style=template="quoteblock",options=("sectionbody",)
+verse-style=template="verseblock"
+
+[blockdef-example]
+delimiter=^={4,}$
+template=exampleblock
+options=sectionbody
+posattrs=style
+NOTE-style=template="admonitionblock",name="note",caption="{note-caption}"
+TIP-style=template="admonitionblock",name="tip",caption="{tip-caption}"
+IMPORTANT-style=template="admonitionblock",name="important",caption="{important-caption}"
+WARNING-style=template="admonitionblock",name="warning",caption="{warning-caption}"
+CAUTION-style=template="admonitionblock",name="caution",caption="{caution-caption}"
+
+# For use by custom filters.
+# DEPRECATED: No longer used, a styled listing block (blockdef-listing) is preferable.
+[blockdef-filter]
+delimiter=^~{4,}$
+template=listingblock
+subs=none
+posattrs=style
+
+#-------
+# Lists
+#-------
+[listdef-bulleted]
+# - bullets.
+delimiter=^\s*- +(?P<text>.+)$
+posattrs=style
+type=bulleted
+tags=bulleted
+callout-style=tags="callout"
+bibliography-style=tags="bibliography"
+
+[listdef-bulleted1]
+# * bullets.
+template::[listdef-bulleted]
+delimiter=^\s*\* +(?P<text>.+)$
+
+[listdef-bulleted2]
+# ** bullets.
+template::[listdef-bulleted]
+delimiter=^\s*\*{2} +(?P<text>.+)$
+
+[listdef-bulleted3]
+# *** bullets.
+template::[listdef-bulleted]
+delimiter=^\s*\*{3} +(?P<text>.+)$
+
+[listdef-bulleted4]
+# **** bullets.
+template::[listdef-bulleted]
+delimiter=^\s*\*{4} +(?P<text>.+)$
+
+[listdef-bulleted5]
+# ***** bullets.
+template::[listdef-bulleted]
+delimiter=^\s*\*{5} +(?P<text>.+)$
+
+[listdef-arabic]
+# Arabic numbering.
+delimiter=^\s*(?P<index>\d+\.) +(?P<text>.+)$
+posattrs=style
+type=numbered
+tags=numbered
+style=arabic
+
+[listdef-loweralpha]
+# Lower alpha numbering.
+template::[listdef-arabic]
+delimiter=^\s*(?P<index>[a-z]\.) +(?P<text>.+)$
+style=loweralpha
+
+[listdef-upperalpha]
+# Upper alpha numbering.
+template::[listdef-arabic]
+delimiter=^\s*(?P<index>[A-Z]\.) +(?P<text>.+)$
+style=upperalpha
+
+[listdef-lowerroman]
+# Lower roman numbering.
+template::[listdef-arabic]
+delimiter=^\s*(?P<index>[ivx]+\)) +(?P<text>.+)$
+style=lowerroman
+
+[listdef-upperroman]
+# Upper roman numbering.
+template::[listdef-arabic]
+delimiter=^\s*(?P<index>[IVX]+\)) +(?P<text>.+)$
+style=upperroman
+
+[listdef-numbered1]
+# . numbering.
+template::[listdef-arabic]
+delimiter=^\s*\. +(?P<text>.+)$
+
+[listdef-numbered2]
+# .. numbering.
+template::[listdef-loweralpha]
+delimiter=^\s*\.{2} +(?P<text>.+)$
+
+[listdef-numbered3]
+# ... numbering.
+template::[listdef-lowerroman]
+delimiter=^\s*\.{3} +(?P<text>.+)$
+
+[listdef-numbered4]
+# .... numbering.
+template::[listdef-upperalpha]
+delimiter=^\s*\.{4} +(?P<text>.+)$
+
+[listdef-numbered5]
+# ..... numbering.
+template::[listdef-upperroman]
+delimiter=^\s*\.{5} +(?P<text>.+)$
+
+[listdef-labeled]
+# label:: item.
+delimiter=^\s*(?P<label>.*[^:])::(\s+(?P<text>.+))?$
+posattrs=style
+type=labeled
+tags=labeled
+vertical-style=tags="labeled"
+horizontal-style=tags="horizontal"
+glossary-style=tags="glossary"
+qanda-style=tags="qanda"
+
+[listdef-labeled2]
+# label;; item.
+template::[listdef-labeled]
+delimiter=^\s*(?P<label>.*[^;]);;(\s+(?P<text>.+))?$
+
+[listdef-labeled3]
+# label::: item.
+template::[listdef-labeled]
+delimiter=^\s*(?P<label>.*[^:]):{3}(\s+(?P<text>.+))?$
+
+[listdef-labeled4]
+# label:::: item.
+template::[listdef-labeled]
+delimiter=^\s*(?P<label>.*[^:]):{4}(\s+(?P<text>.+))?$
+
+[listdef-callout]
+posattrs=style
+delimiter=^<?(?P<index>\d*>) +(?P<text>.+)$
+type=callout
+tags=callout
+style=arabic
+
+# DEPRECATED: Old list syntax.
+[listdef-qanda]
+posattrs=style
+delimiter=^\s*(?P<label>.*\S)\?\?$
+type=labeled
+tags=qanda
+
+# DEPRECATED: Old list syntax.
+[listdef-bibliography]
+posattrs=style
+delimiter=^\+ +(?P<text>.+)$
+type=bulleted
+tags=bibliography
+
+# DEPRECATED: Old list syntax.
+[listdef-glossary]
+delimiter=^(?P<label>.*\S):-$
+posattrs=style
+type=labeled
+tags=glossary
+
+#-------
+# Tables
+#-------
+[tabledef-default]
+delimiter=^\|={3,}$
+posattrs=style
+template=table
+default-style=tags="default"
+verse-style=tags="verse"
+literal-style=tags="literal",subs=["specialcharacters"]
+emphasis-style=tags="emphasis"
+strong-style=tags="strong"
+monospaced-style=tags="monospaced"
+header-style=tags="header"
+asciidoc-style=tags="asciidoc",subs=[],filter='python "{asciidoc-file}" -b {backend} {asciidoc-args}{lang? -a "lang={lang}@"}{icons? -a icons -a "iconsdir={iconsdir}"}{imagesdir? -a "imagesdir={imagesdir}"}{data-uri? -a data-uri} -a "indir={indir}"{trace? -a "trace={trace}"} -s -'
+
+[tabledef-nested]
+# Same as [tabledef-default] but with different delimiter and separator.
+delimiter=^!={3,}$
+separator=((?<!\S)((?P<span>[\d.]+)(?P<op>[*+]))?(?P<align>[<\^>.]{,3})?(?P<style>[a-z])?)?!
+posattrs=style
+template=table
+verse-style=tags="verse"
+literal-style=tags="literal",subs=["specialcharacters"]
+emphasis-style=tags="emphasis"
+strong-style=tags="strong"
+monospaced-style=tags="monospaced"
+header-style=tags="header"
+asciidoc-style=tags="asciidoc",subs=[],filter='python "{asciidoc-file}" -b {backend} {asciidoc-args}{lang? -a "lang={lang}@"} -s -'
+
+#----------------------------------------
+# Common block and macro markup templates
+#----------------------------------------
+[comment-inlinemacro]
+# Outputs nothing.
+
+[comment-blockmacro]
+# Outputs nothing.
+
+[pass-blockmacro]
+{passtext}
+
+[pass-inlinemacro]
+template::[pass-blockmacro]
+
+[passblock]
+|
+
+[filter-image-blockmacro]
+# Synthesize missing target attribute for filter generated file names.
+# The tag split | ensures missing target file names are auto-generated
+# before the filter is executed, the remainder (the [image-blockmacro])
+# is excuted after the filter to ensure data URI encoding comes after
+# the image is created.
+{target%}{counter2:target-number}
+{target%}{set2:target:{docname}__{target-number}.png}
+|
+template::[image-blockmacro]
+
+#----------------------------------
+# Default special section templates
+#----------------------------------
+[abstract]
+template::[sect1]
+
+[colophon]
+template::[sect1]
+
+[dedication]
+template::[sect1]
+
+[preface]
+template::[sect1]
+
+[appendix]
+template::[sect1]
+
+[glossary]
+template::[sect1]
+
+[bibliography]
+template::[sect1]
+
+[index]
+template::[sect1]
+
+[synopsis]
+template::[sect1]
+
+#--------------------------------------------------------------------
+# Deprecated old table definitions.
+#
+
+[old_tabledef-default]
+fillchar=-
+format=fixed
+
+[old_tabledef-csv]
+fillchar=~
+format=csv
+
+[old_tabledef-dsv]
+fillchar=_
+format=dsv
+
+# End of deprecated old table definitions.
+#--------------------------------------------------------------------
diff --git a/doc/www/asciidoc.py b/doc/www/asciidoc.py
new file mode 100755 (executable)
index 0000000..7846de3
--- /dev/null
@@ -0,0 +1,5902 @@
+#!/usr/bin/env python
+"""
+asciidoc - converts an AsciiDoc text file to HTML or DocBook
+
+Copyright (C) 2002-2010 Stuart Rackham. Free use of this software is granted
+under the terms of the GNU General Public License (GPL).
+"""
+
+import sys, os, re, time, traceback, tempfile, subprocess, codecs, locale, unicodedata
+
+### Used by asciidocapi.py ###
+VERSION = '8.6.5'           # See CHANGLOG file for version history.
+
+MIN_PYTHON_VERSION = 2.4    # Require this version of Python or better.
+
+#---------------------------------------------------------------------------
+# Program constants.
+#---------------------------------------------------------------------------
+DEFAULT_BACKEND = 'html'
+DEFAULT_DOCTYPE = 'article'
+# Allowed substitution options for List, Paragraph and DelimitedBlock
+# definition subs entry.
+SUBS_OPTIONS = ('specialcharacters','quotes','specialwords',
+    'replacements', 'attributes','macros','callouts','normal','verbatim',
+    'none','replacements2')
+# Default value for unspecified subs and presubs configuration file entries.
+SUBS_NORMAL = ('specialcharacters','quotes','attributes',
+    'specialwords','replacements','macros','replacements2')
+SUBS_VERBATIM = ('specialcharacters','callouts')
+
+NAME_RE = r'(?u)[^\W\d][-\w]*'  # Valid section or attribute name.
+OR, AND = ',', '+'              # Attribute list separators.
+
+
+#---------------------------------------------------------------------------
+# Utility functions and classes.
+#---------------------------------------------------------------------------
+
+class EAsciiDoc(Exception): pass
+
+class OrderedDict(dict):
+    """
+    Dictionary ordered by insertion order.
+    Python Cookbook: Ordered Dictionary, Submitter: David Benjamin.
+    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
+    """
+    def __init__(self, d=None, **kwargs):
+        self._keys = []
+        if d is None: d = kwargs
+        dict.__init__(self, d)
+    def __delitem__(self, key):
+        dict.__delitem__(self, key)
+        self._keys.remove(key)
+    def __setitem__(self, key, item):
+        dict.__setitem__(self, key, item)
+        if key not in self._keys: self._keys.append(key)
+    def clear(self):
+        dict.clear(self)
+        self._keys = []
+    def copy(self):
+        d = dict.copy(self)
+        d._keys = self._keys[:]
+        return d
+    def items(self):
+        return zip(self._keys, self.values())
+    def keys(self):
+        return self._keys
+    def popitem(self):
+        try:
+            key = self._keys[-1]
+        except IndexError:
+            raise KeyError('dictionary is empty')
+        val = self[key]
+        del self[key]
+        return (key, val)
+    def setdefault(self, key, failobj = None):
+        dict.setdefault(self, key, failobj)
+        if key not in self._keys: self._keys.append(key)
+    def update(self, d=None, **kwargs):
+        if d is None:
+            d = kwargs
+        dict.update(self, d)
+        for key in d.keys():
+            if key not in self._keys: self._keys.append(key)
+    def values(self):
+        return map(self.get, self._keys)
+
+class AttrDict(dict):
+    """
+    Like a dictionary except values can be accessed as attributes i.e. obj.foo
+    can be used in addition to obj['foo'].
+    If an item is not present None is returned.
+    """
+    def __getattr__(self, key):
+        try: return self[key]
+        except KeyError: return None
+    def __setattr__(self, key, value):
+        self[key] = value
+    def __delattr__(self, key):
+        try: del self[key]
+        except KeyError, k: raise AttributeError, k
+    def __repr__(self):
+        return '<AttrDict ' + dict.__repr__(self) + '>'
+    def __getstate__(self):
+        return dict(self)
+    def __setstate__(self,value):
+        for k,v in value.items(): self[k]=v
+
+class InsensitiveDict(dict):
+    """
+    Like a dictionary except key access is case insensitive.
+    Keys are stored in lower case.
+    """
+    def __getitem__(self, key):
+        return dict.__getitem__(self, key.lower())
+    def __setitem__(self, key, value):
+        dict.__setitem__(self, key.lower(), value)
+    def has_key(self, key):
+        return dict.has_key(self,key.lower())
+    def get(self, key, default=None):
+        return dict.get(self, key.lower(), default)
+    def update(self, dict):
+        for k,v in dict.items():
+            self[k] = v
+    def setdefault(self, key, default = None):
+        return dict.setdefault(self, key.lower(), default)
+
+
+class Trace(object):
+    """
+    Used in conjunction with the 'trace' attribute to generate diagnostic
+    output. There is a single global instance of this class named trace.
+    """
+    SUBS_NAMES = ('specialcharacters','quotes','specialwords',
+                  'replacements', 'attributes','macros','callouts',
+                  'replacements2')
+    def __init__(self):
+        self.name_re = ''        # Regexp pattern to match trace names.
+        self.linenos = True
+        self.offset = 0
+    def __call__(self, name, before, after=None):
+        """
+        Print trace message if tracing is on and the trace 'name' matches the
+        document 'trace' attribute (treated as a regexp).
+        'before' is the source text before substitution; 'after' text is the
+        source text after substitutuion.
+        The 'before' and 'after' messages are only printed if they differ.
+        """
+        name_re = document.attributes.get('trace')
+        if name_re == 'subs':    # Alias for all the inline substitutions.
+            name_re = '|'.join(self.SUBS_NAMES)
+        self.name_re = name_re
+        if self.name_re is not None:
+            msg = message.format(name, 'TRACE: ', self.linenos, offset=self.offset)
+            if before != after and re.match(self.name_re,name):
+                if is_array(before):
+                    before = '\n'.join(before)
+                if after is None:
+                    msg += '\n%s\n' % before
+                else:
+                    if is_array(after):
+                        after = '\n'.join(after)
+                    msg += '\n<<<\n%s\n>>>\n%s\n' % (before,after)
+                message.stderr(msg)
+
+class Message:
+    """
+    Message functions.
+    """
+    PROG = os.path.basename(os.path.splitext(__file__)[0])
+
+    def __init__(self):
+        # Set to True or False to globally override line numbers method
+        # argument. Has no effect when set to None.
+        self.linenos = None
+        self.messages = []
+
+    def stdout(self,msg):
+        print msg
+
+    def stderr(self,msg=''):
+        self.messages.append(msg)
+        if __name__ == '__main__':
+            sys.stderr.write('%s: %s%s' % (self.PROG, msg, os.linesep))
+
+    def verbose(self, msg,linenos=True):
+        if config.verbose:
+            msg = self.format(msg,linenos=linenos)
+            self.stderr(msg)
+
+    def warning(self, msg,linenos=True,offset=0):
+        msg = self.format(msg,'WARNING: ',linenos,offset=offset)
+        document.has_warnings = True
+        self.stderr(msg)
+
+    def deprecated(self, msg, linenos=True):
+        msg = self.format(msg, 'DEPRECATED: ', linenos)
+        self.stderr(msg)
+
+    def format(self, msg, prefix='', linenos=True, cursor=None, offset=0):
+        """Return formatted message string."""
+        if self.linenos is not False and ((linenos or self.linenos) and reader.cursor):
+            if cursor is None:
+                cursor = reader.cursor
+            prefix += '%s: line %d: ' % (os.path.basename(cursor[0]),cursor[1]+offset)
+        return prefix + msg
+
+    def error(self, msg, cursor=None, halt=False):
+        """
+        Report fatal error.
+        If halt=True raise EAsciiDoc exception.
+        If halt=False don't exit application, continue in the hope of reporting
+        all fatal errors finishing with a non-zero exit code.
+        """
+        if halt:
+            raise EAsciiDoc, self.format(msg,linenos=False,cursor=cursor)
+        else:
+            msg = self.format(msg,'ERROR: ',cursor=cursor)
+            self.stderr(msg)
+            document.has_errors = True
+
+    def unsafe(self, msg):
+        self.error('unsafe: '+msg)
+
+
+def userdir():
+    """
+    Return user's home directory or None if it is not defined.
+    """
+    result = os.path.expanduser('~')
+    if result == '~':
+        result = None
+    return result
+
+def localapp():
+    """
+    Return True if we are not executing the system wide version
+    i.e. the configuration is in the executable's directory.
+    """
+    return os.path.isfile(os.path.join(APP_DIR, 'asciidoc.conf'))
+
+def file_in(fname, directory):
+    """Return True if file fname resides inside directory."""
+    assert os.path.isfile(fname)
+    # Empty directory (not to be confused with None) is the current directory.
+    if directory == '':
+        directory = os.getcwd()
+    else:
+        assert os.path.isdir(directory)
+        directory = os.path.realpath(directory)
+    fname = os.path.realpath(fname)
+    return os.path.commonprefix((directory, fname)) == directory
+
+def safe():
+    return document.safe
+
+def is_safe_file(fname, directory=None):
+    # A safe file must reside in directory directory (defaults to the source
+    # file directory).
+    if directory is None:
+        if document.infile == '<stdin>':
+           return not safe()
+        directory = os.path.dirname(document.infile)
+    elif directory == '':
+        directory = '.'
+    return (
+        not safe()
+        or file_in(fname, directory)
+        or file_in(fname, APP_DIR)
+        or file_in(fname, CONF_DIR)
+    )
+
+def safe_filename(fname, parentdir):
+    """
+    Return file name which must reside in the parent file directory.
+    Return None if file is not found or not safe.
+    """
+    if not os.path.isabs(fname):
+        # Include files are relative to parent document
+        # directory.
+        fname = os.path.normpath(os.path.join(parentdir,fname))
+    if not os.path.isfile(fname):
+        message.warning('include file not found: %s' % fname)
+        return None
+    if not is_safe_file(fname, parentdir):
+        message.unsafe('include file: %s' % fname)
+        return None
+    return fname
+
+def assign(dst,src):
+    """Assign all attributes from 'src' object to 'dst' object."""
+    for a,v in src.__dict__.items():
+        setattr(dst,a,v)
+
+def strip_quotes(s):
+    """Trim white space and, if necessary, quote characters from s."""
+    s = s.strip()
+    # Strip quotation mark characters from quoted strings.
+    if len(s) >= 3 and s[0] == '"' and s[-1] == '"':
+        s = s[1:-1]
+    return s
+
+def is_re(s):
+    """Return True if s is a valid regular expression else return False."""
+    try: re.compile(s)
+    except: return False
+    else: return True
+
+def re_join(relist):
+    """Join list of regular expressions re1,re2,... to single regular
+    expression (re1)|(re2)|..."""
+    if len(relist) == 0:
+        return None
+    result = []
+    # Delete named groups to avoid ambiguity.
+    for s in relist:
+        result.append(re.sub(r'\?P<\S+?>','',s))
+    result = ')|('.join(result)
+    result = '('+result+')'
+    return result
+
+def validate(value,rule,errmsg):
+    """Validate value against rule expression. Throw EAsciiDoc exception with
+    errmsg if validation fails."""
+    try:
+        if not eval(rule.replace('$',str(value))):
+            raise EAsciiDoc,errmsg
+    except Exception:
+        raise EAsciiDoc,errmsg
+    return value
+
+def lstrip_list(s):
+    """
+    Return list with empty items from start of list removed.
+    """
+    for i in range(len(s)):
+        if s[i]: break
+    else:
+        return []
+    return s[i:]
+
+def rstrip_list(s):
+    """
+    Return list with empty items from end of list removed.
+    """
+    for i in range(len(s)-1,-1,-1):
+        if s[i]: break
+    else:
+        return []
+    return s[:i+1]
+
+def strip_list(s):
+    """
+    Return list with empty items from start and end of list removed.
+    """
+    s = lstrip_list(s)
+    s = rstrip_list(s)
+    return s
+
+def is_array(obj):
+    """
+    Return True if object is list or tuple type.
+    """
+    return isinstance(obj,list) or isinstance(obj,tuple)
+
+def dovetail(lines1, lines2):
+    """
+    Append list or tuple of strings 'lines2' to list 'lines1'.  Join the last
+    non-blank item in 'lines1' with the first non-blank item in 'lines2' into a
+    single string.
+    """
+    assert is_array(lines1)
+    assert is_array(lines2)
+    lines1 = strip_list(lines1)
+    lines2 = strip_list(lines2)
+    if not lines1 or not lines2:
+        return list(lines1) + list(lines2)
+    result = list(lines1[:-1])
+    result.append(lines1[-1] + lines2[0])
+    result += list(lines2[1:])
+    return result
+
+def dovetail_tags(stag,content,etag):
+    """Merge the end tag with the first content line and the last
+    content line with the end tag. This ensures verbatim elements don't
+    include extraneous opening and closing line breaks."""
+    return dovetail(dovetail(stag,content), etag)
+
+def parse_attributes(attrs,dict):
+    """Update a dictionary with name/value attributes from the attrs string.
+    The attrs string is a comma separated list of values and keyword name=value
+    pairs. Values must preceed keywords and are named '1','2'... The entire
+    attributes list is named '0'. If keywords are specified string values must
+    be quoted. Examples:
+
+    attrs: ''
+    dict: {}
+
+    attrs: 'hello,world'
+    dict: {'2': 'world', '0': 'hello,world', '1': 'hello'}
+
+    attrs: '"hello", planet="earth"'
+    dict: {'planet': 'earth', '0': '"hello",planet="earth"', '1': 'hello'}
+    """
+    def f(*args,**keywords):
+        # Name and add aguments '1','2'... to keywords.
+        for i in range(len(args)):
+            if not str(i+1) in keywords:
+                keywords[str(i+1)] = args[i]
+        return keywords
+
+    if not attrs:
+        return
+    dict['0'] = attrs
+    # Replace line separators with spaces so line spanning works.
+    s = re.sub(r'\s', ' ', attrs)
+    try:
+        d = eval('f('+s+')')
+        # Attributes must evaluate to strings, numbers or None.
+        for v in d.values():
+            if not (isinstance(v,str) or isinstance(v,int) or isinstance(v,float) or v is None):
+                raise Exception
+    except Exception:
+        s = s.replace('"','\\"')
+        s = s.split(',')
+        s = map(lambda x: '"' + x.strip() + '"', s)
+        s = ','.join(s)
+        try:
+            d = eval('f('+s+')')
+        except Exception:
+            return  # If there's a syntax error leave with {0}=attrs.
+        for k in d.keys():  # Drop any empty positional arguments.
+            if d[k] == '': del d[k]
+    dict.update(d)
+    assert len(d) > 0
+
+def parse_named_attributes(s,attrs):
+    """Update a attrs dictionary with name="value" attributes from the s string.
+    Returns False if invalid syntax.
+    Example:
+    attrs: 'star="sun",planet="earth"'
+    dict: {'planet':'earth', 'star':'sun'}
+    """
+    def f(**keywords): return keywords
+
+    try:
+        d = eval('f('+s+')')
+        attrs.update(d)
+        return True
+    except Exception:
+        return False
+
+def parse_list(s):
+    """Parse comma separated string of Python literals. Return a tuple of of
+    parsed values."""
+    try:
+        result = eval('tuple(['+s+'])')
+    except Exception:
+        raise EAsciiDoc,'malformed list: '+s
+    return result
+
+def parse_options(options,allowed,errmsg):
+    """Parse comma separated string of unquoted option names and return as a
+    tuple of valid options. 'allowed' is a list of allowed option values.
+    If allowed=() then all legitimate names are allowed.
+    'errmsg' is an error message prefix if an illegal option error is thrown."""
+    result = []
+    if options:
+        for s in re.split(r'\s*,\s*',options):
+            if (allowed and s not in allowed) or not is_name(s):
+                raise EAsciiDoc,'%s: %s' % (errmsg,s)
+            result.append(s)
+    return tuple(result)
+
+def symbolize(s):
+    """Drop non-symbol characters and convert to lowercase."""
+    return re.sub(r'(?u)[^\w\-_]', '', s).lower()
+
+def is_name(s):
+    """Return True if s is valid attribute, macro or tag name
+    (starts with alpha containing alphanumeric and dashes only)."""
+    return re.match(r'^'+NAME_RE+r'$',s) is not None
+
+def subs_quotes(text):
+    """Quoted text is marked up and the resulting text is
+    returned."""
+    keys = config.quotes.keys()
+    for q in keys:
+        i = q.find('|')
+        if i != -1 and q != '|' and q != '||':
+            lq = q[:i]      # Left quote.
+            rq = q[i+1:]    # Right quote.
+        else:
+            lq = rq = q
+        tag = config.quotes[q]
+        if not tag: continue
+        # Unconstrained quotes prefix the tag name with a hash.
+        if tag[0] == '#':
+            tag = tag[1:]
+            # Unconstrained quotes can appear anywhere.
+            reo = re.compile(r'(?msu)(^|.)(\[(?P<attrlist>[^[\]]+?)\])?' \
+                    + r'(?:' + re.escape(lq) + r')' \
+                    + r'(?P<content>.+?)(?:'+re.escape(rq)+r')')
+        else:
+            # The text within constrained quotes must be bounded by white space.
+            # Non-word (\W) characters are allowed at boundaries to accomodate
+            # enveloping quotes and punctuation e.g. a='x', ('x'), 'x', ['x'].
+            reo = re.compile(r'(?msu)(^|[^\w;:}])(\[(?P<attrlist>[^[\]]+?)\])?' \
+                + r'(?:' + re.escape(lq) + r')' \
+                + r'(?P<content>\S|\S.*?\S)(?:'+re.escape(rq)+r')(?=\W|$)')
+        pos = 0
+        while True:
+            mo = reo.search(text,pos)
+            if not mo: break
+            if text[mo.start()] == '\\':
+                # Delete leading backslash.
+                text = text[:mo.start()] + text[mo.start()+1:]
+                # Skip past start of match.
+                pos = mo.start() + 1
+            else:
+                attrlist = {}
+                parse_attributes(mo.group('attrlist'), attrlist)
+                stag,etag = config.tag(tag, attrlist)
+                s = mo.group(1) + stag + mo.group('content') + etag
+                text = text[:mo.start()] + s + text[mo.end():]
+                pos = mo.start() + len(s)
+    return text
+
+def subs_tag(tag,dict={}):
+    """Perform attribute substitution and split tag string returning start, end
+    tag tuple (c.f. Config.tag())."""
+    if not tag:
+        return [None,None]
+    s = subs_attrs(tag,dict)
+    if not s:
+        message.warning('tag \'%s\' dropped: contains undefined attribute' % tag)
+        return [None,None]
+    result = s.split('|')
+    if len(result) == 1:
+        return result+[None]
+    elif len(result) == 2:
+        return result
+    else:
+        raise EAsciiDoc,'malformed tag: %s' % tag
+
+def parse_entry(entry, dict=None, unquote=False, unique_values=False,
+        allow_name_only=False, escape_delimiter=True):
+    """Parse name=value entry to dictionary 'dict'. Return tuple (name,value)
+    or None if illegal entry.
+    If name= then value is set to ''.
+    If name and allow_name_only=True then value is set to ''.
+    If name! and allow_name_only=True then value is set to None.
+    Leading and trailing white space is striped from 'name' and 'value'.
+    'name' can contain any printable characters.
+    If the '=' delimiter character is allowed in  the 'name' then
+    it must be escaped with a backslash and escape_delimiter must be True.
+    If 'unquote' is True leading and trailing double-quotes are stripped from
+    'name' and 'value'.
+    If unique_values' is True then dictionary entries with the same value are
+    removed before the parsed entry is added."""
+    if escape_delimiter:
+        mo = re.search(r'(?:[^\\](=))',entry)
+    else:
+        mo = re.search(r'(=)',entry)
+    if mo:  # name=value entry.
+        if mo.group(1):
+            name = entry[:mo.start(1)]
+            if escape_delimiter:
+                name = name.replace(r'\=','=')  # Unescape \= in name.
+            value = entry[mo.end(1):]
+    elif allow_name_only and entry:         # name or name! entry.
+        name = entry
+        if name[-1] == '!':
+            name = name[:-1]
+            value = None
+        else:
+            value = ''
+    else:
+        return None
+    if unquote:
+        name = strip_quotes(name)
+        if value is not None:
+            value = strip_quotes(value)
+    else:
+        name = name.strip()
+        if value is not None:
+            value = value.strip()
+    if not name:
+        return None
+    if dict is not None:
+        if unique_values:
+            for k,v in dict.items():
+                if v == value: del dict[k]
+        dict[name] = value
+    return name,value
+
+def parse_entries(entries, dict, unquote=False, unique_values=False,
+        allow_name_only=False,escape_delimiter=True):
+    """Parse name=value entries from  from lines of text in 'entries' into
+    dictionary 'dict'. Blank lines are skipped."""
+    entries = config.expand_templates(entries)
+    for entry in entries:
+        if entry and not parse_entry(entry, dict, unquote, unique_values,
+                allow_name_only, escape_delimiter):
+            raise EAsciiDoc,'malformed section entry: %s' % entry
+
+def dump_section(name,dict,f=sys.stdout):
+    """Write parameters in 'dict' as in configuration file section format with
+    section 'name'."""
+    f.write('[%s]%s' % (name,writer.newline))
+    for k,v in dict.items():
+        k = str(k)
+        k = k.replace('=',r'\=')    # Escape = in name.
+        # Quote if necessary.
+        if len(k) != len(k.strip()):
+            k = '"'+k+'"'
+        if v and len(v) != len(v.strip()):
+            v = '"'+v+'"'
+        if v is None:
+            # Don't dump undefined attributes.
+            continue
+        else:
+            s = k+'='+v
+        if s[0] == '#':
+            s = '\\' + s    # Escape so not treated as comment lines.
+        f.write('%s%s' % (s,writer.newline))
+    f.write(writer.newline)
+
+def update_attrs(attrs,dict):
+    """Update 'attrs' dictionary with parsed attributes in dictionary 'dict'."""
+    for k,v in dict.items():
+        if not is_name(k):
+            raise EAsciiDoc,'illegal attribute name: %s' % k
+        attrs[k] = v
+
+def is_attr_defined(attrs,dic):
+    """
+    Check if the sequence of attributes is defined in dictionary 'dic'.
+    Valid 'attrs' sequence syntax:
+    <attr> Return True if single attrbiute is defined.
+    <attr1>,<attr2>,... Return True if one or more attributes are defined.
+    <attr1>+<attr2>+... Return True if all the attributes are defined.
+    """
+    if OR in attrs:
+        for a in attrs.split(OR):
+            if dic.get(a.strip()) is not None:
+                return True
+        else: return False
+    elif AND in attrs:
+        for a in attrs.split(AND):
+            if dic.get(a.strip()) is None:
+                return False
+        else: return True
+    else:
+        return dic.get(attrs.strip()) is not None
+
+def filter_lines(filter_cmd, lines, attrs={}):
+    """
+    Run 'lines' through the 'filter_cmd' shell command and return the result.
+    The 'attrs' dictionary contains additional filter attributes.
+    """
+    def findfilter(name,dir,filter):
+        """Find filter file 'fname' with style name 'name' in directory
+        'dir'. Return found file path or None if not found."""
+        if name:
+            result = os.path.join(dir,'filters',name,filter)
+            if os.path.isfile(result):
+                return result
+        result = os.path.join(dir,'filters',filter)
+        if os.path.isfile(result):
+            return result
+        return None
+
+    # Return input lines if there's not filter.
+    if not filter_cmd or not filter_cmd.strip():
+        return lines
+    # Perform attributes substitution on the filter command.
+    s = subs_attrs(filter_cmd, attrs)
+    if not s:
+        message.error('undefined filter attribute in command: %s' % filter_cmd)
+        return []
+    filter_cmd = s.strip()
+    # Parse for quoted and unquoted command and command tail.
+    # Double quoted.
+    mo = re.match(r'^"(?P<cmd>[^"]+)"(?P<tail>.*)$', filter_cmd)
+    if not mo:
+        # Single quoted.
+        mo = re.match(r"^'(?P<cmd>[^']+)'(?P<tail>.*)$", filter_cmd)
+        if not mo:
+            # Unquoted catch all.
+            mo = re.match(r'^(?P<cmd>\S+)(?P<tail>.*)$', filter_cmd)
+    cmd = mo.group('cmd').strip()
+    found = None
+    if not os.path.dirname(cmd):
+        # Filter command has no directory path so search filter directories.
+        filtername = attrs.get('style')
+        d = document.attributes.get('docdir')
+        if d:
+            found = findfilter(filtername, d, cmd)
+        if not found:
+            if USER_DIR:
+                found = findfilter(filtername, USER_DIR, cmd)
+            if not found:
+                if localapp():
+                    found = findfilter(filtername, APP_DIR, cmd)
+                else:
+                    found = findfilter(filtername, CONF_DIR, cmd)
+    else:
+        if os.path.isfile(cmd):
+            found = cmd
+        else:
+            message.warning('filter not found: %s' % cmd)
+    if found:
+        filter_cmd = '"' + found + '"' + mo.group('tail')
+    if sys.platform == 'win32':
+        # Windows doesn't like running scripts directly so explicitly
+        # specify interpreter.
+        if found:
+            if cmd.endswith('.py'):
+                filter_cmd = 'python ' + filter_cmd
+            elif cmd.endswith('.rb'):
+                filter_cmd = 'ruby ' + filter_cmd
+    message.verbose('filtering: ' + filter_cmd)
+    try:
+        p = subprocess.Popen(filter_cmd, shell=True,
+                stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+        output = p.communicate(os.linesep.join(lines))[0]
+    except Exception:
+        raise EAsciiDoc,'filter error: %s: %s' % (filter_cmd, sys.exc_info()[1])
+    if output:
+        result = [s.rstrip() for s in output.split(os.linesep)]
+    else:
+        result = []
+    filter_status = p.wait()
+    if filter_status:
+        message.warning('filter non-zero exit code: %s: returned %d' %
+               (filter_cmd, filter_status))
+    if lines and not result:
+        message.warning('no output from filter: %s' % filter_cmd)
+    return result
+
+def system(name, args, is_macro=False, attrs=None):
+    """
+    Evaluate a system attribute ({name:args}) or system block macro
+    (name::[args]).
+    If is_macro is True then we are processing a system block macro otherwise
+    it's a system attribute.
+    The attrs dictionary is updated by the counter and set system attributes.
+    NOTE: The include1 attribute is used internally by the include1::[] macro
+    and is not for public use.
+    """
+    if is_macro:
+        syntax = '%s::[%s]' % (name,args)
+        separator = '\n'
+    else:
+        syntax = '{%s:%s}' % (name,args)
+        separator = writer.newline
+    if name not in ('eval','eval3','sys','sys2','sys3','include','include1','counter','counter2','set','set2','template'):
+        if is_macro:
+            msg = 'illegal system macro name: %s' % name
+        else:
+            msg = 'illegal system attribute name: %s' % name
+        message.warning(msg)
+        return None
+    if is_macro:
+        s = subs_attrs(args)
+        if s is None:
+            message.warning('skipped %s: undefined attribute in: %s' % (name,args))
+            return None
+        args = s
+    if name != 'include1':
+        message.verbose('evaluating: %s' % syntax)
+    if safe() and name not in ('include','include1'):
+        message.unsafe(syntax)
+        return None
+    result = None
+    if name in ('eval','eval3'):
+        try:
+            result = eval(args)
+            if result is True:
+                result = ''
+            elif result is False:
+                result = None
+            elif result is not None:
+                result = str(result)
+        except Exception:
+            message.warning('%s: evaluation error' % syntax)
+    elif name in ('sys','sys2','sys3'):
+        result = ''
+        fd,tmp = tempfile.mkstemp()
+        os.close(fd)
+        try:
+            cmd = args
+            cmd = cmd + (' > %s' % tmp)
+            if name == 'sys2':
+                cmd = cmd + ' 2>&1'
+            if os.system(cmd):
+                message.warning('%s: non-zero exit status' % syntax)
+            try:
+                if os.path.isfile(tmp):
+                    lines = [s.rstrip() for s in open(tmp)]
+                else:
+                    lines = []
+            except Exception:
+                raise EAsciiDoc,'%s: temp file read error' % syntax
+            result = separator.join(lines)
+        finally:
+            if os.path.isfile(tmp):
+                os.remove(tmp)
+    elif name in ('counter','counter2'):
+        mo = re.match(r'^(?P<attr>[^:]*?)(:(?P<seed>.*))?$', args)
+        attr = mo.group('attr')
+        seed = mo.group('seed')
+        if seed and (not re.match(r'^\d+$', seed) and len(seed) > 1):
+            message.warning('%s: illegal counter seed: %s' % (syntax,seed))
+            return None
+        if not is_name(attr):
+            message.warning('%s: illegal attribute name' % syntax)
+            return None
+        value = document.attributes.get(attr)
+        if value:
+            if not re.match(r'^\d+$', value) and len(value) > 1:
+                message.warning('%s: illegal counter value: %s'
+                                % (syntax,value))
+                return None
+            if re.match(r'^\d+$', value):
+                expr = value + '+1'
+            else:
+                expr = 'chr(ord("%s")+1)' % value
+            try:
+                result = str(eval(expr))
+            except Exception:
+                message.warning('%s: evaluation error: %s' % (syntax, expr))
+        else:
+            if seed:
+                result = seed
+            else:
+                result = '1'
+        document.attributes[attr] = result
+        if attrs is not None:
+            attrs[attr] = result
+        if name == 'counter2':
+            result = ''
+    elif name in ('set','set2'):
+        mo = re.match(r'^(?P<attr>[^:]*?)(:(?P<value>.*))?$', args)
+        attr = mo.group('attr')
+        value = mo.group('value')
+        if value is None:
+            value = ''
+        if attr.endswith('!'):
+            attr = attr[:-1]
+            value = None
+        if not is_name(attr):
+            message.warning('%s: illegal attribute name' % syntax)
+        else:
+            if attrs is not None:
+                attrs[attr] = value
+            if name != 'set2':  # set2 only updates local attributes.
+                document.attributes[attr] = value
+        if value is None:
+            result = None
+        else:
+            result = ''
+    elif name == 'include':
+        if not os.path.exists(args):
+            message.warning('%s: file does not exist' % syntax)
+        elif not is_safe_file(args):
+            message.unsafe(syntax)
+        else:
+            result = [s.rstrip() for s in open(args)]
+            if result:
+                result = subs_attrs(result)
+                result = separator.join(result)
+                result = result.expandtabs(reader.tabsize)
+            else:
+                result = ''
+    elif name == 'include1':
+        result = separator.join(config.include1[args])
+    elif name == 'template':
+        if not args in config.sections:
+            message.warning('%s: template does not exist' % syntax)
+        else:
+            result = []
+            for line in  config.sections[args]:
+                line = subs_attrs(line)
+                if line is not None:
+                    result.append(line)
+            result = '\n'.join(result)
+    else:
+        assert False
+    if result and name in ('eval3','sys3'):
+        macros.passthroughs.append(result)
+        result = '\x07' + str(len(macros.passthroughs)-1) + '\x07'
+    return result
+
+def subs_attrs(lines, dictionary=None):
+    """Substitute 'lines' of text with attributes from the global
+    document.attributes dictionary and from 'dictionary' ('dictionary'
+    entries take precedence). Return a tuple of the substituted lines.  'lines'
+    containing undefined attributes are deleted. If 'lines' is a string then
+    return a string.
+
+    - Attribute references are substituted in the following order: simple,
+      conditional, system.
+    - Attribute references inside 'dictionary' entry values are substituted.
+    """
+
+    def end_brace(text,start):
+        """Return index following end brace that matches brace at start in
+        text."""
+        assert text[start] == '{'
+        n = 0
+        result = start
+        for c in text[start:]:
+            # Skip braces that are followed by a backslash.
+            if result == len(text)-1 or text[result+1] != '\\':
+                if c == '{': n = n + 1
+                elif c == '}': n = n - 1
+            result = result + 1
+            if n == 0: break
+        return result
+
+    if type(lines) == str:
+        string_result = True
+        lines = [lines]
+    else:
+        string_result = False
+    if dictionary is None:
+        attrs = document.attributes
+    else:
+        # Remove numbered document attributes so they don't clash with
+        # attribute list positional attributes.
+        attrs = {}
+        for k,v in document.attributes.items():
+            if not re.match(r'^\d+$', k):
+                attrs[k] = v
+        # Substitute attribute references inside dictionary values.
+        for k,v in dictionary.items():
+            if v is None:
+                del dictionary[k]
+            else:
+                v = subs_attrs(str(v))
+                if v is None:
+                    del dictionary[k]
+                else:
+                    dictionary[k] = v
+        attrs.update(dictionary)
+    # Substitute all attributes in all lines.
+    result = []
+    for line in lines:
+        # Make it easier for regular expressions.
+        line = line.replace('\\{','{\\')
+        line = line.replace('\\}','}\\')
+        # Expand simple attributes ({name}).
+        # Nested attributes not allowed.
+        reo = re.compile(r'(?su)\{(?P<name>[^\\\W][-\w]*?)\}(?!\\)')
+        pos = 0
+        while True:
+            mo = reo.search(line,pos)
+            if not mo: break
+            s =  attrs.get(mo.group('name'))
+            if s is None:
+                pos = mo.end()
+            else:
+                s = str(s)
+                line = line[:mo.start()] + s + line[mo.end():]
+                pos = mo.start() + len(s)
+        # Expand conditional attributes.
+        # Single name -- higher precedence.
+        reo1 = re.compile(r'(?su)\{(?P<name>[^\\\W][-\w]*?)' \
+                          r'(?P<op>\=|\?|!|#|%|@|\$)' \
+                          r'(?P<value>.*?)\}(?!\\)')
+        # Multiple names (n1,n2,... or n1+n2+...) -- lower precedence.
+        reo2 = re.compile(r'(?su)\{(?P<name>[^\\\W][-\w'+OR+AND+r']*?)' \
+                          r'(?P<op>\=|\?|!|#|%|@|\$)' \
+                          r'(?P<value>.*?)\}(?!\\)')
+        for reo in [reo1,reo2]:
+            pos = 0
+            while True:
+                mo = reo.search(line,pos)
+                if not mo: break
+                attr = mo.group()
+                name =  mo.group('name')
+                if reo == reo2:
+                    if OR in name:
+                        sep = OR
+                    else:
+                        sep = AND
+                    names = [s.strip() for s in name.split(sep) if s.strip() ]
+                    for n in names:
+                        if not re.match(r'^[^\\\W][-\w]*$',n):
+                            message.error('illegal attribute syntax: %s' % attr)
+                    if sep == OR:
+                        # Process OR name expression: n1,n2,...
+                        for n in names:
+                            if attrs.get(n) is not None:
+                                lval = ''
+                                break
+                        else:
+                            lval = None
+                    else:
+                        # Process AND name expression: n1+n2+...
+                        for n in names:
+                            if attrs.get(n) is None:
+                                lval = None
+                                break
+                        else:
+                            lval = ''
+                else:
+                    lval =  attrs.get(name)
+                op = mo.group('op')
+                # mo.end() not good enough because '{x={y}}' matches '{x={y}'.
+                end = end_brace(line,mo.start())
+                rval = line[mo.start('value'):end-1]
+                UNDEFINED = '{zzzzz}'
+                if lval is None:
+                    if op == '=': s = rval
+                    elif op == '?': s = ''
+                    elif op == '!': s = rval
+                    elif op == '#': s = UNDEFINED   # So the line is dropped.
+                    elif op == '%': s = rval
+                    elif op in ('@','$'):
+                        s = UNDEFINED               # So the line is dropped.
+                    else:
+                        assert False, 'illegal attribute: %s' % attr
+                else:
+                    if op == '=': s = lval
+                    elif op == '?': s = rval
+                    elif op == '!': s = ''
+                    elif op == '#': s = rval
+                    elif op == '%': s = UNDEFINED   # So the line is dropped.
+                    elif op in ('@','$'):
+                        v = re.split(r'(?<!\\):',rval)
+                        if len(v) not in (2,3):
+                            message.error('illegal attribute syntax: %s' % attr)
+                            s = ''
+                        elif not is_re('^'+v[0]+'$'):
+                            message.error('illegal attribute regexp: %s' % attr)
+                            s = ''
+                        else:
+                            v = [s.replace('\\:',':') for s in v]
+                            re_mo = re.match('^'+v[0]+'$',lval)
+                            if op == '@':
+                                if re_mo:
+                                    s = v[1]         # {<name>@<re>:<v1>[:<v2>]}
+                                else:
+                                    if len(v) == 3:   # {<name>@<re>:<v1>:<v2>}
+                                        s = v[2]
+                                    else:             # {<name>@<re>:<v1>}
+                                        s = ''
+                            else:
+                                if re_mo:
+                                    if len(v) == 2:   # {<name>$<re>:<v1>}
+                                        s = v[1]
+                                    elif v[1] == '':  # {<name>$<re>::<v2>}
+                                        s = UNDEFINED # So the line is dropped.
+                                    else:             # {<name>$<re>:<v1>:<v2>}
+                                        s = v[1]
+                                else:
+                                    if len(v) == 2:   # {<name>$<re>:<v1>}
+                                        s = UNDEFINED # So the line is dropped.
+                                    else:             # {<name>$<re>:<v1>:<v2>}
+                                        s = v[2]
+                    else:
+                        assert False, 'illegal attribute: %s' % attr
+                s = str(s)
+                line = line[:mo.start()] + s + line[end:]
+                pos = mo.start() + len(s)
+        # Drop line if it contains  unsubstituted {name} references.
+        skipped = re.search(r'(?su)\{[^\\\W][-\w]*?\}(?!\\)', line)
+        if skipped:
+            trace('dropped line', line)
+            continue;
+        # Expand system attributes (eval has precedence).
+        reos = [
+            re.compile(r'(?su)\{(?P<action>eval):(?P<expr>.*?)\}(?!\\)'),
+            re.compile(r'(?su)\{(?P<action>[^\\\W][-\w]*?):(?P<expr>.*?)\}(?!\\)'),
+        ]
+        skipped = False
+        for reo in reos:
+            pos = 0
+            while True:
+                mo = reo.search(line,pos)
+                if not mo: break
+                expr = mo.group('expr')
+                action = mo.group('action')
+                expr = expr.replace('{\\','{')
+                expr = expr.replace('}\\','}')
+                s = system(action, expr, attrs=dictionary)
+                if dictionary is not None and action in ('counter','counter2','set','set2'):
+                    # These actions create and update attributes.
+                    attrs.update(dictionary)
+                if s is None:
+                    # Drop line if the action returns None.
+                    skipped = True
+                    break
+                line = line[:mo.start()] + s + line[mo.end():]
+                pos = mo.start() + len(s)
+            if skipped:
+                break
+        if not skipped:
+            # Remove backslash from escaped entries.
+            line = line.replace('{\\','{')
+            line = line.replace('}\\','}')
+            result.append(line)
+    if string_result:
+        if result:
+            return '\n'.join(result)
+        else:
+            return None
+    else:
+        return tuple(result)
+
+def char_encoding():
+    encoding = document.attributes.get('encoding')
+    if encoding:
+        try:
+            codecs.lookup(encoding)
+        except LookupError,e:
+            raise EAsciiDoc,str(e)
+    return encoding
+
+def char_len(s):
+    return len(char_decode(s))
+
+east_asian_widths = {'W': 2,   # Wide
+                     'F': 2,   # Full-width (wide)
+                     'Na': 1,  # Narrow
+                     'H': 1,   # Half-width (narrow)
+                     'N': 1,   # Neutral (not East Asian, treated as narrow)
+                     'A': 1}   # Ambiguous (s/b wide in East Asian context,
+                               # narrow otherwise, but that doesn't work)
+"""Mapping of result codes from `unicodedata.east_asian_width()` to character
+column widths."""
+
+def column_width(s):
+    text = char_decode(s)
+    if isinstance(text, unicode):
+        width = 0
+        for c in text:
+            width += east_asian_widths[unicodedata.east_asian_width(c)]
+        return width
+    else:
+        return len(text)
+
+def char_decode(s):
+    if char_encoding():
+        try:
+            return s.decode(char_encoding())
+        except Exception:
+            raise EAsciiDoc, \
+                "'%s' codec can't decode \"%s\"" % (char_encoding(), s)
+    else:
+        return s
+
+def char_encode(s):
+    if char_encoding():
+        return s.encode(char_encoding())
+    else:
+        return s
+
+def time_str(t):
+    """Convert seconds since the Epoch to formatted local time string."""
+    t = time.localtime(t)
+    s = time.strftime('%H:%M:%S',t)
+    if time.daylight and t.tm_isdst == 1:
+        result = s + ' ' + time.tzname[1]
+    else:
+        result = s + ' ' + time.tzname[0]
+    # Attempt to convert the localtime to the output encoding.
+    try:
+        result = char_encode(result.decode(locale.getdefaultlocale()[1]))
+    except Exception:
+        pass
+    return result
+
+def date_str(t):
+    """Convert seconds since the Epoch to formatted local date string."""
+    t = time.localtime(t)
+    return time.strftime('%Y-%m-%d',t)
+
+
+class Lex:
+    """Lexical analysis routines. Static methods and attributes only."""
+    prev_element = None
+    prev_cursor = None
+    def __init__(self):
+        raise AssertionError,'no class instances allowed'
+    @staticmethod
+    def next():
+        """Returns class of next element on the input (None if EOF).  The
+        reader is assumed to be at the first line following a previous element,
+        end of file or line one.  Exits with the reader pointing to the first
+        line of the next element or EOF (leading blank lines are skipped)."""
+        reader.skip_blank_lines()
+        if reader.eof(): return None
+        # Optimization: If we've already checked for an element at this
+        # position return the element.
+        if Lex.prev_element and Lex.prev_cursor == reader.cursor:
+            return Lex.prev_element
+        if AttributeEntry.isnext():
+            result = AttributeEntry
+        elif AttributeList.isnext():
+            result = AttributeList
+        elif BlockTitle.isnext() and not tables_OLD.isnext():
+            result = BlockTitle
+        elif Title.isnext():
+            if AttributeList.style() == 'float':
+                result = FloatingTitle
+            else:
+                result = Title
+        elif macros.isnext():
+            result = macros.current
+        elif lists.isnext():
+            result = lists.current
+        elif blocks.isnext():
+            result = blocks.current
+        elif tables_OLD.isnext():
+            result = tables_OLD.current
+        elif tables.isnext():
+            result = tables.current
+        else:
+            if not paragraphs.isnext():
+                raise EAsciiDoc,'paragraph expected'
+            result = paragraphs.current
+        # Optimization: Cache answer.
+        Lex.prev_cursor = reader.cursor
+        Lex.prev_element = result
+        return result
+
+    @staticmethod
+    def canonical_subs(options):
+        """Translate composite subs values."""
+        if len(options) == 1:
+            if options[0] == 'none':
+                options = ()
+            elif options[0] == 'normal':
+                options = config.subsnormal
+            elif options[0] == 'verbatim':
+                options = config.subsverbatim
+        return options
+
+    @staticmethod
+    def subs_1(s,options):
+        """Perform substitution specified in 'options' (in 'options' order)."""
+        if not s:
+            return s
+        if document.attributes.get('plaintext') is not None:
+            options = ('specialcharacters',)
+        result = s
+        options = Lex.canonical_subs(options)
+        for o in options:
+            if o == 'specialcharacters':
+                result = config.subs_specialchars(result)
+            elif o == 'attributes':
+                result = subs_attrs(result)
+            elif o == 'quotes':
+                result = subs_quotes(result)
+            elif o == 'specialwords':
+                result = config.subs_specialwords(result)
+            elif o in ('replacements','replacements2'):
+                result = config.subs_replacements(result,o)
+            elif o == 'macros':
+                result = macros.subs(result)
+            elif o == 'callouts':
+                result = macros.subs(result,callouts=True)
+            else:
+                raise EAsciiDoc,'illegal substitution option: %s' % o
+            trace(o, s, result)
+            if not result:
+                break
+        return result
+
+    @staticmethod
+    def subs(lines,options):
+        """Perform inline processing specified by 'options' (in 'options'
+        order) on sequence of 'lines'."""
+        if not lines or not options:
+            return lines
+        options = Lex.canonical_subs(options)
+        # Join lines so quoting can span multiple lines.
+        para = '\n'.join(lines)
+        if 'macros' in options:
+            para = macros.extract_passthroughs(para)
+        for o in options:
+            if o == 'attributes':
+                # If we don't substitute attributes line-by-line then a single
+                # undefined attribute will drop the entire paragraph.
+                lines = subs_attrs(para.split('\n'))
+                para = '\n'.join(lines)
+            else:
+                para = Lex.subs_1(para,(o,))
+        if 'macros' in options:
+            para = macros.restore_passthroughs(para)
+        return para.splitlines()
+
+    @staticmethod
+    def set_margin(lines, margin=0):
+        """Utility routine that sets the left margin to 'margin' space in a
+        block of non-blank lines."""
+        # Calculate width of block margin.
+        lines = list(lines)
+        width = len(lines[0])
+        for s in lines:
+            i = re.search(r'\S',s).start()
+            if i < width: width = i
+        # Strip margin width from all lines.
+        for i in range(len(lines)):
+            lines[i] = ' '*margin + lines[i][width:]
+        return lines
+
+#---------------------------------------------------------------------------
+# Document element classes parse AsciiDoc reader input and write DocBook writer
+# output.
+#---------------------------------------------------------------------------
+class Document(object):
+
+    # doctype property.
+    def getdoctype(self):
+        return self.attributes.get('doctype')
+    def setdoctype(self,doctype):
+        self.attributes['doctype'] = doctype
+    doctype = property(getdoctype,setdoctype)
+
+    # backend property.
+    def getbackend(self):
+        return self.attributes.get('backend')
+    def setbackend(self,backend):
+        if backend:
+            backend = self.attributes.get('backend-alias-' + backend, backend)
+        self.attributes['backend'] = backend
+    backend = property(getbackend,setbackend)
+
+    def __init__(self):
+        self.infile = None      # Source file name.
+        self.outfile = None     # Output file name.
+        self.attributes = InsensitiveDict()
+        self.level = 0          # 0 => front matter. 1,2,3 => sect1,2,3.
+        self.has_errors = False # Set true if processing errors were flagged.
+        self.has_warnings = False # Set true if warnings were flagged.
+        self.safe = False       # Default safe mode.
+    def update_attributes(self,attrs=None):
+        """
+        Set implicit attributes and attributes in 'attrs'.
+        """
+        t = time.time()
+        self.attributes['localtime'] = time_str(t)
+        self.attributes['localdate'] = date_str(t)
+        self.attributes['asciidoc-version'] = VERSION
+        self.attributes['asciidoc-file'] = APP_FILE
+        self.attributes['asciidoc-dir'] = APP_DIR
+        self.attributes['asciidoc-confdir'] = CONF_DIR
+        self.attributes['user-dir'] = USER_DIR
+        if config.verbose:
+            self.attributes['verbose'] = ''
+        # Update with configuration file attributes.
+        if attrs:
+            self.attributes.update(attrs)
+        # Update with command-line attributes.
+        self.attributes.update(config.cmd_attrs)
+        # Extract miscellaneous configuration section entries from attributes.
+        if attrs:
+            config.load_miscellaneous(attrs)
+        config.load_miscellaneous(config.cmd_attrs)
+        self.attributes['newline'] = config.newline
+        # File name related attributes can't be overridden.
+        if self.infile is not None:
+            if self.infile and os.path.exists(self.infile):
+                t = os.path.getmtime(self.infile)
+            elif self.infile == '<stdin>':
+                t = time.time()
+            else:
+                t = None
+            if t:
+                self.attributes['doctime'] = time_str(t)
+                self.attributes['docdate'] = date_str(t)
+            if self.infile != '<stdin>':
+                self.attributes['infile'] = self.infile
+                self.attributes['indir'] = os.path.dirname(self.infile)
+                self.attributes['docfile'] = self.infile
+                self.attributes['docdir'] = os.path.dirname(self.infile)
+                self.attributes['docname'] = os.path.splitext(
+                        os.path.basename(self.infile))[0]
+        if self.outfile:
+            if self.outfile != '<stdout>':
+                self.attributes['outfile'] = self.outfile
+                self.attributes['outdir'] = os.path.dirname(self.outfile)
+                if self.infile == '<stdin>':
+                    self.attributes['docname'] = os.path.splitext(
+                            os.path.basename(self.outfile))[0]
+                ext = os.path.splitext(self.outfile)[1][1:]
+            elif config.outfilesuffix:
+                ext = config.outfilesuffix[1:]
+            else:
+                ext = ''
+            if ext:
+                self.attributes['filetype'] = ext
+                self.attributes['filetype-'+ext] = ''
+    def load_lang(self):
+        """
+        Load language configuration file.
+        """
+        lang = self.attributes.get('lang')
+        if lang is None:
+            filename = 'lang-en.conf'   # Default language file.
+        else:
+            filename = 'lang-' + lang + '.conf'
+        if config.load_from_dirs(filename):
+            self.attributes['lang'] = lang  # Reinstate new lang attribute.
+        else:
+            if lang is None:
+                # The default language file must exist.
+                message.error('missing conf file: %s' % filename, halt=True)
+            else:
+                message.warning('missing language conf file: %s' % filename)
+    def set_deprecated_attribute(self,old,new):
+        """
+        Ensures the 'old' name of an attribute that was renamed to 'new' is
+        still honored.
+        """
+        if self.attributes.get(new) is None:
+            if self.attributes.get(old) is not None:
+                self.attributes[new] = self.attributes[old]
+        else:
+            self.attributes[old] = self.attributes[new]
+    def consume_attributes_and_comments(self,comments_only=False,noblanks=False):
+        """
+        Returns True if one or more attributes or comments were consumed.
+        If 'noblanks' is True then consumation halts if a blank line is
+        encountered.
+        """
+        result = False
+        finished = False
+        while not finished:
+            finished = True
+            if noblanks and not reader.read_next(): return result
+            if blocks.isnext() and 'skip' in blocks.current.options:
+                result = True
+                finished = False
+                blocks.current.translate()
+            if noblanks and not reader.read_next(): return result
+            if macros.isnext() and macros.current.name == 'comment':
+                result = True
+                finished = False
+                macros.current.translate()
+            if not comments_only:
+                if AttributeEntry.isnext():
+                    result = True
+                    finished = False
+                    AttributeEntry.translate()
+                if AttributeList.isnext():
+                    result = True
+                    finished = False
+                    AttributeList.translate()
+        return result
+    def parse_header(self,doctype,backend):
+        """
+        Parses header, sets corresponding document attributes and finalizes
+        document doctype and backend properties.
+        Returns False if the document does not have a header.
+        'doctype' and 'backend' are the doctype and backend option values
+        passed on the command-line, None if no command-line option was not
+        specified.
+        """
+        assert self.level == 0
+        # Skip comments and attribute entries that preceed the header.
+        self.consume_attributes_and_comments()
+        if doctype is not None:
+            # Command-line overrides header.
+            self.doctype = doctype
+        elif self.doctype is None:
+            # Was not set on command-line or in document header.
+            self.doctype = DEFAULT_DOCTYPE
+        # Process document header.
+        has_header = (Title.isnext() and Title.level == 0
+                      and AttributeList.style() != 'float')
+        if self.doctype == 'manpage' and not has_header:
+            message.error('manpage document title is mandatory',halt=True)
+        if has_header:
+            Header.parse()
+        # Command-line entries override header derived entries.
+        self.attributes.update(config.cmd_attrs)
+        # DEPRECATED: revision renamed to revnumber.
+        self.set_deprecated_attribute('revision','revnumber')
+        # DEPRECATED: date renamed to revdate.
+        self.set_deprecated_attribute('date','revdate')
+        if doctype is not None:
+            # Command-line overrides header.
+            self.doctype = doctype
+        if backend is not None:
+            # Command-line overrides header.
+            self.backend = backend
+        elif self.backend is None:
+            # Was not set on command-line or in document header.
+            self.backend = DEFAULT_BACKEND
+        else:
+            # Has been set in document header.
+            self.backend = self.backend # Translate alias in header.
+        assert self.doctype in ('article','manpage','book'), 'illegal document type'
+        return has_header
+    def translate(self,has_header):
+        if self.doctype == 'manpage':
+            # Translate mandatory NAME section.
+            if Lex.next() is not Title:
+                message.error('name section expected')
+            else:
+                Title.translate()
+                if Title.level != 1:
+                    message.error('name section title must be at level 1')
+                if not isinstance(Lex.next(),Paragraph):
+                    message.error('malformed name section body')
+                lines = reader.read_until(r'^$')
+                s = ' '.join(lines)
+                mo = re.match(r'^(?P<manname>.*?)\s+-\s+(?P<manpurpose>.*)$',s)
+                if not mo:
+                    message.error('malformed name section body')
+                self.attributes['manname'] = mo.group('manname').strip()
+                self.attributes['manpurpose'] = mo.group('manpurpose').strip()
+                names = [s.strip() for s in self.attributes['manname'].split(',')]
+                if len(names) > 9:
+                    message.warning('to many manpage names')
+                for i,name in enumerate(names):
+                    self.attributes['manname%d' % (i+1)] = name
+        if has_header:
+            # Do postponed substitutions (backend confs have been loaded).
+            self.attributes['doctitle'] = Title.dosubs(self.attributes['doctitle'])
+            if config.header_footer:
+                hdr = config.subs_section('header',{})
+                writer.write(hdr,trace='header')
+            if 'title' in self.attributes:
+                del self.attributes['title']
+            self.consume_attributes_and_comments()
+            if self.doctype in ('article','book'):
+                # Translate 'preamble' (untitled elements between header
+                # and first section title).
+                if Lex.next() is not Title:
+                    stag,etag = config.section2tags('preamble')
+                    writer.write(stag,trace='preamble open')
+                    Section.translate_body()
+                    writer.write(etag,trace='preamble close')
+            elif self.doctype == 'manpage' and 'name' in config.sections:
+                writer.write(config.subs_section('name',{}), trace='name')
+        else:
+            self.process_author_names()
+            if config.header_footer:
+                hdr = config.subs_section('header',{})
+                writer.write(hdr,trace='header')
+            if Lex.next() is not Title:
+                Section.translate_body()
+        # Process remaining sections.
+        while not reader.eof():
+            if Lex.next() is not Title:
+                raise EAsciiDoc,'section title expected'
+            Section.translate()
+        Section.setlevel(0) # Write remaining unwritten section close tags.
+        # Substitute document parameters and write document footer.
+        if config.header_footer:
+            ftr = config.subs_section('footer',{})
+            writer.write(ftr,trace='footer')
+    def parse_author(self,s):
+        """ Return False if the author is malformed."""
+        attrs = self.attributes # Alias for readability.
+        s = s.strip()
+        mo = re.match(r'^(?P<name1>[^<>\s]+)'
+                '(\s+(?P<name2>[^<>\s]+))?'
+                '(\s+(?P<name3>[^<>\s]+))?'
+                '(\s+<(?P<email>\S+)>)?$',s)
+        if not mo:
+            # Names that don't match the formal specification.
+            if s:
+                attrs['firstname'] = s
+            return
+        firstname = mo.group('name1')
+        if mo.group('name3'):
+            middlename = mo.group('name2')
+            lastname = mo.group('name3')
+        else:
+            middlename = None
+            lastname = mo.group('name2')
+        firstname = firstname.replace('_',' ')
+        if middlename:
+            middlename = middlename.replace('_',' ')
+        if lastname:
+            lastname = lastname.replace('_',' ')
+        email = mo.group('email')
+        if firstname:
+            attrs['firstname'] = firstname
+        if middlename:
+            attrs['middlename'] = middlename
+        if lastname:
+            attrs['lastname'] = lastname
+        if email:
+            attrs['email'] = email
+        return
+    def process_author_names(self):
+        """ Calculate any missing author related attributes."""
+        attrs = self.attributes # Alias for readability.
+        firstname = attrs.get('firstname','')
+        middlename = attrs.get('middlename','')
+        lastname = attrs.get('lastname','')
+        author = attrs.get('author')
+        initials = attrs.get('authorinitials')
+        if author and not (firstname or middlename or lastname):
+            self.parse_author(author)
+            attrs['author'] = author.replace('_',' ')
+            self.process_author_names()
+            return
+        if not author:
+            author = '%s %s %s' % (firstname, middlename, lastname)
+            author = author.strip()
+            author = re.sub(r'\s+',' ', author)
+        if not initials:
+            initials = (char_decode(firstname)[:1] +
+                       char_decode(middlename)[:1] + char_decode(lastname)[:1])
+            initials = char_encode(initials).upper()
+        names = [firstname,middlename,lastname,author,initials]
+        for i,v in enumerate(names):
+            v = config.subs_specialchars(v)
+            v = subs_attrs(v)
+            names[i] = v
+        firstname,middlename,lastname,author,initials = names
+        if firstname:
+            attrs['firstname'] = firstname
+        if middlename:
+            attrs['middlename'] = middlename
+        if lastname:
+            attrs['lastname'] = lastname
+        if author:
+            attrs['author'] = author
+        if initials:
+            attrs['authorinitials'] = initials
+        if author:
+            attrs['authored'] = ''
+
+
+class Header:
+    """Static methods and attributes only."""
+    REV_LINE_RE = r'^(\D*(?P<revnumber>.*?),)?(?P<revdate>.*?)(:\s*(?P<revremark>.*))?$'
+    RCS_ID_RE = r'^\$Id: \S+ (?P<revnumber>\S+) (?P<revdate>\S+) \S+ (?P<author>\S+) (\S+ )?\$$'
+    def __init__(self):
+        raise AssertionError,'no class instances allowed'
+    @staticmethod
+    def parse():
+        assert Lex.next() is Title and Title.level == 0
+        attrs = document.attributes # Alias for readability.
+        # Postpone title subs until backend conf files have been loaded.
+        Title.translate(skipsubs=True)
+        attrs['doctitle'] = Title.attributes['title']
+        document.consume_attributes_and_comments(noblanks=True)
+        s = reader.read_next()
+        mo = None
+        if s:
+            # Process first header line after the title that is not a comment
+            # or an attribute entry.
+            s = reader.read()
+            mo = re.match(Header.RCS_ID_RE,s)
+            if not mo:
+                document.parse_author(s)
+                document.consume_attributes_and_comments(noblanks=True)
+                if reader.read_next():
+                    # Process second header line after the title that is not a
+                    # comment or an attribute entry.
+                    s = reader.read()
+                    s = subs_attrs(s)
+                    if s:
+                        mo = re.match(Header.RCS_ID_RE,s)
+                        if not mo:
+                            mo = re.match(Header.REV_LINE_RE,s)
+            document.consume_attributes_and_comments(noblanks=True)
+        s = attrs.get('revnumber')
+        if s:
+            mo = re.match(Header.RCS_ID_RE,s)
+        if mo:
+            revnumber = mo.group('revnumber')
+            if revnumber:
+                attrs['revnumber'] = revnumber.strip()
+            author = mo.groupdict().get('author')
+            if author and 'firstname' not in attrs:
+                document.parse_author(author)
+            revremark = mo.groupdict().get('revremark')
+            if revremark is not None:
+                revremark = [revremark]
+                # Revision remarks can continue on following lines.
+                while reader.read_next():
+                    if document.consume_attributes_and_comments(noblanks=True):
+                        break
+                    revremark.append(reader.read())
+                revremark = Lex.subs(revremark,['normal'])
+                revremark = '\n'.join(revremark).strip()
+                attrs['revremark'] = revremark
+            revdate = mo.group('revdate')
+            if revdate:
+                attrs['revdate'] = revdate.strip()
+            elif revnumber or revremark:
+                # Set revision date to ensure valid DocBook revision.
+                attrs['revdate'] = attrs['docdate']
+        document.process_author_names()
+        if document.doctype == 'manpage':
+            # manpage title formatted like mantitle(manvolnum).
+            mo = re.match(r'^(?P<mantitle>.*)\((?P<manvolnum>.*)\)$',
+                          attrs['doctitle'])
+            if not mo:
+                message.error('malformed manpage title')
+            else:
+                mantitle = mo.group('mantitle').strip()
+                mantitle = subs_attrs(mantitle)
+                if mantitle is None:
+                    message.error('undefined attribute in manpage title')
+                # mantitle is lowered only if in ALL CAPS
+                if mantitle == mantitle.upper():
+                    mantitle = mantitle.lower()
+                attrs['mantitle'] = mantitle;
+                attrs['manvolnum'] = mo.group('manvolnum').strip()
+
+class AttributeEntry:
+    """Static methods and attributes only."""
+    pattern = None
+    subs = None
+    name = None
+    name2 = None
+    value = None
+    attributes = {}     # Accumulates all the parsed attribute entries.
+    def __init__(self):
+        raise AssertionError,'no class instances allowed'
+    @staticmethod
+    def isnext():
+        result = False  # Assume not next.
+        if not AttributeEntry.pattern:
+            pat = document.attributes.get('attributeentry-pattern')
+            if not pat:
+                message.error("[attributes] missing 'attributeentry-pattern' entry")
+            AttributeEntry.pattern = pat
+        line = reader.read_next()
+        if line:
+            # Attribute entry formatted like :<name>[.<name2>]:[ <value>]
+            mo = re.match(AttributeEntry.pattern,line)
+            if mo:
+                AttributeEntry.name = mo.group('attrname')
+                AttributeEntry.name2 = mo.group('attrname2')
+                AttributeEntry.value = mo.group('attrvalue') or ''
+                AttributeEntry.value = AttributeEntry.value.strip()
+                result = True
+        return result
+    @staticmethod
+    def translate():
+        assert Lex.next() is AttributeEntry
+        attr = AttributeEntry    # Alias for brevity.
+        reader.read()            # Discard attribute entry from reader.
+        while attr.value.endswith(' +'):
+            if not reader.read_next(): break
+            attr.value = attr.value[:-1] + reader.read().strip()
+        if attr.name2 is not None:
+            # Configuration file attribute.
+            if attr.name2 != '':
+                # Section entry attribute.
+                section = {}
+                # Some sections can have name! syntax.
+                if attr.name in ('attributes','miscellaneous') and attr.name2[-1] == '!':
+                    section[attr.name] = [attr.name2]
+                else:
+                   section[attr.name] = ['%s=%s' % (attr.name2,attr.value)]
+                config.load_sections(section)
+                config.load_miscellaneous(config.conf_attrs)
+            else:
+                # Markup template section attribute.
+                if attr.name in config.sections:
+                    config.sections[attr.name] = [attr.value]
+                else:
+                    message.warning('missing configuration section: %s' % attr.name)
+        else:
+            # Normal attribute.
+            if attr.name[-1] == '!':
+                # Names like name! undefine the attribute.
+                attr.name = attr.name[:-1]
+                attr.value = None
+            # Strip white space and illegal name chars.
+            attr.name = re.sub(r'(?u)[^\w\-_]', '', attr.name).lower()
+            # Don't override most command-line attributes.
+            if attr.name in config.cmd_attrs \
+                    and attr.name not in ('trace','numbered'):
+                return
+            # Update document attributes with attribute value.
+            if attr.value is not None:
+                mo = re.match(r'^pass:(?P<attrs>.*)\[(?P<value>.*)\]$', attr.value)
+                if mo:
+                    # Inline passthrough syntax.
+                    attr.subs = mo.group('attrs')
+                    attr.value = mo.group('value')  # Passthrough.
+                else:
+                    # Default substitution.
+                    # DEPRECATED: attributeentry-subs
+                    attr.subs = document.attributes.get('attributeentry-subs',
+                                'specialcharacters,attributes')
+                attr.subs = parse_options(attr.subs, SUBS_OPTIONS,
+                            'illegal substitution option')
+                attr.value = Lex.subs((attr.value,), attr.subs)
+                attr.value = writer.newline.join(attr.value)
+                document.attributes[attr.name] = attr.value
+            elif attr.name in document.attributes:
+                del document.attributes[attr.name]
+            attr.attributes[attr.name] = attr.value
+
+class AttributeList:
+    """Static methods and attributes only."""
+    pattern = None
+    match = None
+    attrs = {}
+    def __init__(self):
+        raise AssertionError,'no class instances allowed'
+    @staticmethod
+    def initialize():
+        if not 'attributelist-pattern' in document.attributes:
+            message.error("[attributes] missing 'attributelist-pattern' entry")
+        AttributeList.pattern = document.attributes['attributelist-pattern']
+    @staticmethod
+    def isnext():
+        result = False  # Assume not next.
+        line = reader.read_next()
+        if line:
+            mo = re.match(AttributeList.pattern, line)
+            if mo:
+                AttributeList.match = mo
+                result = True
+        return result
+    @staticmethod
+    def translate():
+        assert Lex.next() is AttributeList
+        reader.read()   # Discard attribute list from reader.
+        attrs = {}
+        d = AttributeList.match.groupdict()
+        for k,v in d.items():
+            if v is not None:
+                if k == 'attrlist':
+                    v = subs_attrs(v)
+                    if v:
+                        parse_attributes(v, attrs)
+                else:
+                    AttributeList.attrs[k] = v
+        AttributeList.subs(attrs)
+        AttributeList.attrs.update(attrs)
+    @staticmethod
+    def subs(attrs):
+        '''Substitute single quoted attribute values normally.'''
+        reo = re.compile(r"^'.*'$")
+        for k,v in attrs.items():
+            if reo.match(str(v)):
+                attrs[k] = Lex.subs_1(v[1:-1],SUBS_NORMAL)
+    @staticmethod
+    def style():
+        return AttributeList.attrs.get('style') or AttributeList.attrs.get('1')
+    @staticmethod
+    def consume(d):
+        """Add attribute list to the dictionary 'd' and reset the
+        list."""
+        if AttributeList.attrs:
+            d.update(AttributeList.attrs)
+            AttributeList.attrs = {}
+            # Generate option attributes.
+            if 'options' in d:
+                options = parse_options(d['options'], (), 'illegal option name')
+                for option in options:
+                    d[option+'-option'] = ''
+
+class BlockTitle:
+    """Static methods and attributes only."""
+    title = None
+    pattern = None
+    def __init__(self):
+        raise AssertionError,'no class instances allowed'
+    @staticmethod
+    def isnext():
+        result = False  # Assume not next.
+        line = reader.read_next()
+        if line:
+            mo = re.match(BlockTitle.pattern,line)
+            if mo:
+                BlockTitle.title = mo.group('title')
+                result = True
+        return result
+    @staticmethod
+    def translate():
+        assert Lex.next() is BlockTitle
+        reader.read()   # Discard title from reader.
+        # Perform title substitutions.
+        if not Title.subs:
+            Title.subs = config.subsnormal
+        s = Lex.subs((BlockTitle.title,), Title.subs)
+        s = writer.newline.join(s)
+        if not s:
+            message.warning('blank block title')
+        BlockTitle.title = s
+    @staticmethod
+    def consume(d):
+        """If there is a title add it to dictionary 'd' then reset title."""
+        if BlockTitle.title:
+            d['title'] = BlockTitle.title
+            BlockTitle.title = None
+
+class Title:
+    """Processes Header and Section titles. Static methods and attributes
+    only."""
+    # Class variables
+    underlines = ('==','--','~~','^^','++') # Levels 0,1,2,3,4.
+    subs = ()
+    pattern = None
+    level = 0
+    attributes = {}
+    sectname = None
+    section_numbers = [0]*len(underlines)
+    dump_dict = {}
+    linecount = None    # Number of lines in title (1 or 2).
+    def __init__(self):
+        raise AssertionError,'no class instances allowed'
+    @staticmethod
+    def translate(skipsubs=False):
+        """Parse the Title.attributes and Title.level from the reader. The
+        real work has already been done by parse()."""
+        assert Lex.next() in (Title,FloatingTitle)
+        # Discard title from reader.
+        for i in range(Title.linecount):
+            reader.read()
+        Title.setsectname()
+        if not skipsubs:
+            Title.attributes['title'] = Title.dosubs(Title.attributes['title'])
+    @staticmethod
+    def dosubs(title):
+        """
+        Perform title substitutions.
+        """
+        if not Title.subs:
+            Title.subs = config.subsnormal
+        title = Lex.subs((title,), Title.subs)
+        title = writer.newline.join(title)
+        if not title:
+            message.warning('blank section title')
+        return title
+    @staticmethod
+    def isnext():
+        lines = reader.read_ahead(2)
+        return Title.parse(lines)
+    @staticmethod
+    def parse(lines):
+        """Parse title at start of lines tuple."""
+        if len(lines) == 0: return False
+        if len(lines[0]) == 0: return False # Title can't be blank.
+        # Check for single-line titles.
+        result = False
+        for level in range(len(Title.underlines)):
+            k = 'sect%s' % level
+            if k in Title.dump_dict:
+                mo = re.match(Title.dump_dict[k], lines[0])
+                if mo:
+                    Title.attributes = mo.groupdict()
+                    Title.level = level
+                    Title.linecount = 1
+                    result = True
+                    break
+        if not result:
+            # Check for double-line titles.
+            if not Title.pattern: return False  # Single-line titles only.
+            if len(lines) < 2: return False
+            title,ul = lines[:2]
+            title_len = column_width(title)
+            ul_len = char_len(ul)
+            if ul_len < 2: return False
+            # Fast elimination check.
+            if ul[:2] not in Title.underlines: return False
+            # Length of underline must be within +-3 of title.
+            if not ((ul_len-3 < title_len < ul_len+3)
+                    # Next test for backward compatibility.
+                    or (ul_len-3 < char_len(title) < ul_len+3)):
+                return False
+            # Check for valid repetition of underline character pairs.
+            s = ul[:2]*((ul_len+1)/2)
+            if ul != s[:ul_len]: return False
+            # Don't be fooled by back-to-back delimited blocks, require at
+            # least one alphanumeric character in title.
+            if not re.search(r'(?u)\w',title): return False
+            mo = re.match(Title.pattern, title)
+            if mo:
+                Title.attributes = mo.groupdict()
+                Title.level = list(Title.underlines).index(ul[:2])
+                Title.linecount = 2
+                result = True
+        # Check for expected pattern match groups.
+        if result:
+            if not 'title' in Title.attributes:
+                message.warning('[titles] entry has no <title> group')
+                Title.attributes['title'] = lines[0]
+            for k,v in Title.attributes.items():
+                if v is None: del Title.attributes[k]
+        try:
+            Title.level += int(document.attributes.get('leveloffset','0'))
+        except:
+            pass
+        Title.attributes['level'] = str(Title.level)
+        return result
+    @staticmethod
+    def load(entries):
+        """Load and validate [titles] section entries dictionary."""
+        if 'underlines' in entries:
+            errmsg = 'malformed [titles] underlines entry'
+            try:
+                underlines = parse_list(entries['underlines'])
+            except Exception:
+                raise EAsciiDoc,errmsg
+            if len(underlines) != len(Title.underlines):
+                raise EAsciiDoc,errmsg
+            for s in underlines:
+                if len(s) !=2:
+                    raise EAsciiDoc,errmsg
+            Title.underlines = tuple(underlines)
+            Title.dump_dict['underlines'] = entries['underlines']
+        if 'subs' in entries:
+            Title.subs = parse_options(entries['subs'], SUBS_OPTIONS,
+                'illegal [titles] subs entry')
+            Title.dump_dict['subs'] = entries['subs']
+        if 'sectiontitle' in entries:
+            pat = entries['sectiontitle']
+            if not pat or not is_re(pat):
+                raise EAsciiDoc,'malformed [titles] sectiontitle entry'
+            Title.pattern = pat
+            Title.dump_dict['sectiontitle'] = pat
+        if 'blocktitle' in entries:
+            pat = entries['blocktitle']
+            if not pat or not is_re(pat):
+                raise EAsciiDoc,'malformed [titles] blocktitle entry'
+            BlockTitle.pattern = pat
+            Title.dump_dict['blocktitle'] = pat
+        # Load single-line title patterns.
+        for k in ('sect0','sect1','sect2','sect3','sect4'):
+            if k in entries:
+                pat = entries[k]
+                if not pat or not is_re(pat):
+                    raise EAsciiDoc,'malformed [titles] %s entry' % k
+                Title.dump_dict[k] = pat
+        # TODO: Check we have either a Title.pattern or at least one
+        # single-line title pattern -- can this be done here or do we need
+        # check routine like the other block checkers?
+    @staticmethod
+    def dump():
+        dump_section('titles',Title.dump_dict)
+    @staticmethod
+    def setsectname():
+        """
+        Set Title section name:
+        If the first positional or 'template' attribute is set use it,
+        next search for section title in [specialsections],
+        if not found use default 'sect<level>' name.
+        """
+        sectname = AttributeList.attrs.get('1')
+        if sectname and sectname != 'float':
+            Title.sectname = sectname
+        elif 'template' in AttributeList.attrs:
+            Title.sectname = AttributeList.attrs['template']
+        else:
+            for pat,sect in config.specialsections.items():
+                mo = re.match(pat,Title.attributes['title'])
+                if mo:
+                    title = mo.groupdict().get('title')
+                    if title is not None:
+                        Title.attributes['title'] = title.strip()
+                    else:
+                        Title.attributes['title'] = mo.group().strip()
+                    Title.sectname = sect
+                    break
+            else:
+                Title.sectname = 'sect%d' % Title.level
+    @staticmethod
+    def getnumber(level):
+        """Return next section number at section 'level' formatted like
+        1.2.3.4."""
+        number = ''
+        for l in range(len(Title.section_numbers)):
+            n = Title.section_numbers[l]
+            if l == 0:
+                continue
+            elif l < level:
+                number = '%s%d.' % (number, n)
+            elif l == level:
+                number = '%s%d.' % (number, n + 1)
+                Title.section_numbers[l] = n + 1
+            elif l > level:
+                # Reset unprocessed section levels.
+                Title.section_numbers[l] = 0
+        return number
+
+
+class FloatingTitle(Title):
+    '''Floated titles are translated differently.'''
+    @staticmethod
+    def isnext():
+        return Title.isnext() and AttributeList.style() == 'float'
+    @staticmethod
+    def translate():
+        assert Lex.next() is FloatingTitle
+        Title.translate()
+        Section.set_id()
+        AttributeList.consume(Title.attributes)
+        template = 'floatingtitle'
+        if template in config.sections:
+            stag,etag = config.section2tags(template,Title.attributes)
+            writer.write(stag,trace='floating title')
+        else:
+            message.warning('missing template section: [%s]' % template)
+
+
+class Section:
+    """Static methods and attributes only."""
+    endtags = []  # Stack of currently open section (level,endtag) tuples.
+    ids = []      # List of already used ids.
+    def __init__(self):
+        raise AssertionError,'no class instances allowed'
+    @staticmethod
+    def savetag(level,etag):
+        """Save section end."""
+        Section.endtags.append((level,etag))
+    @staticmethod
+    def setlevel(level):
+        """Set document level and write open section close tags up to level."""
+        while Section.endtags and Section.endtags[-1][0] >= level:
+            writer.write(Section.endtags.pop()[1],trace='section close')
+        document.level = level
+    @staticmethod
+    def gen_id(title):
+        """
+        The normalized value of the id attribute is an NCName according to
+        the 'Namespaces in XML' Recommendation:
+        NCName          ::=     NCNameStartChar NCNameChar*
+        NCNameChar      ::=     NameChar - ':'
+        NCNameStartChar ::=     Letter | '_'
+        NameChar        ::=     Letter | Digit | '.' | '-' | '_' | ':'
+        """
+        # Replace non-alpha numeric characters in title with underscores and
+        # convert to lower case.
+        base_ident = char_encode(re.sub(r'(?u)\W+', '_',
+                char_decode(title)).strip('_').lower())
+        # Prefix the ID name with idprefix attribute or underscore if not
+        # defined. Prefix ensures the ID does not clash with existing IDs.
+        idprefix = document.attributes.get('idprefix','_')
+        base_ident = idprefix + base_ident
+        i = 1
+        while True:
+            if i == 1:
+                ident = base_ident
+            else:
+                ident = '%s_%d' % (base_ident, i)
+            if ident not in Section.ids:
+                Section.ids.append(ident)
+                return ident
+            else:
+                ident = base_ident
+            i += 1
+    @staticmethod
+    def set_id():
+        if not document.attributes.get('sectids') is None \
+                and 'id' not in AttributeList.attrs:
+            # Generate ids for sections.
+            AttributeList.attrs['id'] = Section.gen_id(Title.attributes['title'])
+    @staticmethod
+    def translate():
+        assert Lex.next() is Title
+        prev_sectname = Title.sectname
+        Title.translate()
+        if Title.level == 0 and document.doctype != 'book':
+            message.error('only book doctypes can contain level 0 sections')
+        if Title.level > document.level \
+                and 'basebackend-docbook' in document.attributes \
+                and prev_sectname in ('colophon','abstract', \
+                    'dedication','glossary','bibliography'):
+            message.error('%s section cannot contain sub-sections' % prev_sectname)
+        if Title.level > document.level+1:
+            # Sub-sections of multi-part book level zero Preface and Appendices
+            # are meant to be out of sequence.
+            if document.doctype == 'book' \
+                    and document.level == 0 \
+                    and Title.level == 2 \
+                    and prev_sectname in ('preface','appendix'):
+                pass
+            else:
+                message.warning('section title out of sequence: '
+                    'expected level %d, got level %d'
+                    % (document.level+1, Title.level))
+        Section.set_id()
+        Section.setlevel(Title.level)
+        if 'numbered' in document.attributes:
+            Title.attributes['sectnum'] = Title.getnumber(document.level)
+        else:
+            Title.attributes['sectnum'] = ''
+        AttributeList.consume(Title.attributes)
+        stag,etag = config.section2tags(Title.sectname,Title.attributes)
+        Section.savetag(Title.level,etag)
+        writer.write(stag,trace='section open: level %d: %s' %
+                (Title.level, Title.attributes['title']))
+        Section.translate_body()
+    @staticmethod
+    def translate_body(terminator=Title):
+        isempty = True
+        next = Lex.next()
+        while next and next is not terminator:
+            if isinstance(terminator,DelimitedBlock) and next is Title:
+                message.error('section title not permitted in delimited block')
+            next.translate()
+            next = Lex.next()
+            isempty = False
+        # The section is not empty if contains a subsection.
+        if next and isempty and Title.level > document.level:
+            isempty = False
+        # Report empty sections if invalid markup will result.
+        if isempty:
+            if document.backend == 'docbook' and Title.sectname != 'index':
+                message.error('empty section is not valid')
+
+class AbstractBlock:
+    def __init__(self):
+        # Configuration parameter names common to all blocks.
+        self.CONF_ENTRIES = ('delimiter','options','subs','presubs','postsubs',
+                             'posattrs','style','.*-style','template','filter')
+        self.start = None   # File reader cursor at start delimiter.
+        self.name=None      # Configuration file section name.
+        # Configuration parameters.
+        self.delimiter=None # Regular expression matching block delimiter.
+        self.delimiter_reo=None # Compiled delimiter.
+        self.template=None  # template section entry.
+        self.options=()     # options entry list.
+        self.presubs=None   # presubs/subs entry list.
+        self.postsubs=()    # postsubs entry list.
+        self.filter=None    # filter entry.
+        self.posattrs=()    # posattrs entry list.
+        self.style=None     # Default style.
+        self.styles=OrderedDict() # Each entry is a styles dictionary.
+        # Before a block is processed it's attributes (from it's
+        # attributes list) are merged with the block configuration parameters
+        # (by self.merge_attributes()) resulting in the template substitution
+        # dictionary (self.attributes) and the block's processing parameters
+        # (self.parameters).
+        self.attributes={}
+        # The names of block parameters.
+        self.PARAM_NAMES=('template','options','presubs','postsubs','filter')
+        self.parameters=None
+        # Leading delimiter match object.
+        self.mo=None
+    def short_name(self):
+        """ Return the text following the last dash in the section name."""
+        i = self.name.rfind('-')
+        if i == -1:
+            return self.name
+        else:
+            return self.name[i+1:]
+    def error(self, msg, cursor=None, halt=False):
+        message.error('[%s] %s' % (self.name,msg), cursor, halt)
+    def is_conf_entry(self,param):
+        """Return True if param matches an allowed configuration file entry
+        name."""
+        for s in self.CONF_ENTRIES:
+            if re.match('^'+s+'$',param):
+                return True
+        return False
+    def load(self,name,entries):
+        """Update block definition from section 'entries' dictionary."""
+        self.name = name
+        self.update_parameters(entries, self, all=True)
+    def update_parameters(self, src, dst=None, all=False):
+        """
+        Parse processing parameters from src dictionary to dst object.
+        dst defaults to self.parameters.
+        If all is True then copy src entries that aren't parameter names.
+        """
+        dst = dst or self.parameters
+        msg = '[%s] malformed entry %%s: %%s' % self.name
+        def copy(obj,k,v):
+            if isinstance(obj,dict):
+                obj[k] = v
+            else:
+                setattr(obj,k,v)
+        for k,v in src.items():
+            if not re.match(r'\d+',k) and not is_name(k):
+                raise EAsciiDoc, msg % (k,v)
+            if k == 'template':
+                if not is_name(v):
+                    raise EAsciiDoc, msg % (k,v)
+                copy(dst,k,v)
+            elif k == 'filter':
+                copy(dst,k,v)
+            elif k == 'options':
+                if isinstance(v,str):
+                    v = parse_options(v, (), msg % (k,v))
+                    # Merge with existing options.
+                    v = tuple(set(dst.options).union(set(v)))
+                copy(dst,k,v)
+            elif k in ('subs','presubs','postsubs'):
+                # Subs is an alias for presubs.
+                if k == 'subs': k = 'presubs'
+                if isinstance(v,str):
+                    v = parse_options(v, SUBS_OPTIONS, msg % (k,v))
+                copy(dst,k,v)
+            elif k == 'delimiter':
+                if v and is_re(v):
+                    copy(dst,k,v)
+                else:
+                    raise EAsciiDoc, msg % (k,v)
+            elif k == 'style':
+                if is_name(v):
+                    copy(dst,k,v)
+                else:
+                    raise EAsciiDoc, msg % (k,v)
+            elif k == 'posattrs':
+                v = parse_options(v, (), msg % (k,v))
+                copy(dst,k,v)
+            else:
+                mo = re.match(r'^(?P<style>.*)-style$',k)
+                if mo:
+                    if not v:
+                        raise EAsciiDoc, msg % (k,v)
+                    style = mo.group('style')
+                    if not is_name(style):
+                        raise EAsciiDoc, msg % (k,v)
+                    d = {}
+                    if not parse_named_attributes(v,d):
+                        raise EAsciiDoc, msg % (k,v)
+                    if 'subs' in d:
+                        # Subs is an alias for presubs.
+                        d['presubs'] = d['subs']
+                        del d['subs']
+                    self.styles[style] = d
+                elif all or k in self.PARAM_NAMES:
+                    copy(dst,k,v) # Derived class specific entries.
+    def get_param(self,name,params=None):
+        """
+        Return named processing parameter from params dictionary.
+        If the parameter is not in params look in self.parameters.
+        """
+        if params and name in params:
+            return params[name]
+        elif name in self.parameters:
+            return self.parameters[name]
+        else:
+            return None
+    def get_subs(self,params=None):
+        """
+        Return (presubs,postsubs) tuple.
+        """
+        presubs = self.get_param('presubs',params)
+        postsubs = self.get_param('postsubs',params)
+        return (presubs,postsubs)
+    def dump(self):
+        """Write block definition to stdout."""
+        write = lambda s: sys.stdout.write('%s%s' % (s,writer.newline))
+        write('['+self.name+']')
+        if self.is_conf_entry('delimiter'):
+            write('delimiter='+self.delimiter)
+        if self.template:
+            write('template='+self.template)
+        if self.options:
+            write('options='+','.join(self.options))
+        if self.presubs:
+            if self.postsubs:
+                write('presubs='+','.join(self.presubs))
+            else:
+                write('subs='+','.join(self.presubs))
+        if self.postsubs:
+            write('postsubs='+','.join(self.postsubs))
+        if self.filter:
+            write('filter='+self.filter)
+        if self.posattrs:
+            write('posattrs='+','.join(self.posattrs))
+        if self.style:
+            write('style='+self.style)
+        if self.styles:
+            for style,d in self.styles.items():
+                s = ''
+                for k,v in d.items(): s += '%s=%r,' % (k,v)
+                write('%s-style=%s' % (style,s[:-1]))
+    def validate(self):
+        """Validate block after the complete configuration has been loaded."""
+        if self.is_conf_entry('delimiter') and not self.delimiter:
+            raise EAsciiDoc,'[%s] missing delimiter' % self.name
+        if self.style:
+            if not is_name(self.style):
+                raise EAsciiDoc, 'illegal style name: %s' % self.style
+            if not self.style in self.styles:
+                if not isinstance(self,List):   # Lists don't have templates.
+                    message.warning('[%s] \'%s\' style not in %s' % (
+                        self.name,self.style,self.styles.keys()))
+        # Check all styles for missing templates.
+        all_styles_have_template = True
+        for k,v in self.styles.items():
+            t = v.get('template')
+            if t and not t in config.sections:
+                # Defer check if template name contains attributes.
+                if not re.search(r'{.+}',t):
+                    message.warning('missing template section: [%s]' % t)
+            if not t:
+                all_styles_have_template = False
+        # Check we have a valid template entry or alternatively that all the
+        # styles have templates.
+        if self.is_conf_entry('template') and not 'skip' in self.options:
+            if self.template:
+                if not self.template in config.sections:
+                    # Defer check if template name contains attributes.
+                    if not re.search(r'{.+}',self.template):
+                        message.warning('missing template section: [%s]'
+                                        % self.template)
+            elif not all_styles_have_template:
+                if not isinstance(self,List): # Lists don't have templates.
+                    message.warning('missing styles templates: [%s]' % self.name)
+    def isnext(self):
+        """Check if this block is next in document reader."""
+        result = False
+        reader.skip_blank_lines()
+        if reader.read_next():
+            if not self.delimiter_reo:
+                # Cache compiled delimiter optimization.
+                self.delimiter_reo = re.compile(self.delimiter)
+            mo = self.delimiter_reo.match(reader.read_next())
+            if mo:
+                self.mo = mo
+                result = True
+        return result
+    def translate(self):
+        """Translate block from document reader."""
+        if not self.presubs:
+            self.presubs = config.subsnormal
+        if reader.cursor:
+            self.start = reader.cursor[:]
+    def merge_attributes(self,attrs,params=[]):
+        """
+        Use the current blocks attribute list (attrs dictionary) to build a
+        dictionary of block processing parameters (self.parameters) and tag
+        substitution attributes (self.attributes).
+
+        1. Copy the default parameters (self.*) to self.parameters.
+        self.parameters are used internally to render the current block.
+        Optional params array of additional parameters.
+
+        2. Copy attrs to self.attributes. self.attributes are used for template
+        and tag substitution in the current block.
+
+        3. If a style attribute was specified update self.parameters with the
+        corresponding style parameters; if there are any style parameters
+        remaining add them to self.attributes (existing attribute list entries
+        take precedence).
+
+        4. Set named positional attributes in self.attributes if self.posattrs
+        was specified.
+
+        5. Finally self.parameters is updated with any corresponding parameters
+        specified in attrs.
+
+        """
+
+        def check_array_parameter(param):
+            # Check the parameter is a sequence type.
+            if not is_array(self.parameters[param]):
+                message.error('malformed presubs attribute: %s' %
+                        self.parameters[param])
+                # Revert to default value.
+                self.parameters[param] = getattr(self,param)
+
+        params = list(self.PARAM_NAMES) + params
+        self.attributes = {}
+        if self.style:
+            # If a default style is defined make it available in the template.
+            self.attributes['style'] = self.style
+        self.attributes.update(attrs)
+        # Calculate dynamic block parameters.
+        # Start with configuration file defaults.
+        self.parameters = AttrDict()
+        for name in params:
+            self.parameters[name] = getattr(self,name)
+        # Load the selected style attributes.
+        posattrs = self.posattrs
+        if posattrs and posattrs[0] == 'style':
+            # Positional attribute style has highest precedence.
+            style = self.attributes.get('1')
+        else:
+            style = None
+        if not style:
+            # Use explicit style attribute, fall back to default style.
+            style = self.attributes.get('style',self.style)
+        if style:
+            if not is_name(style):
+                message.error('illegal style name: %s' % style)
+                style = self.style
+            # Lists have implicit styles and do their own style checks.
+            elif style not in self.styles and not isinstance(self,List):
+                message.warning('missing style: [%s]: %s' % (self.name,style))
+                style = self.style
+            if style in self.styles:
+                self.attributes['style'] = style
+                for k,v in self.styles[style].items():
+                    if k == 'posattrs':
+                        posattrs = v
+                    elif k in params:
+                        self.parameters[k] = v
+                    elif not k in self.attributes:
+                        # Style attributes don't take precedence over explicit.
+                        self.attributes[k] = v
+        # Set named positional attributes.
+        for i,v in enumerate(posattrs):
+            if str(i+1) in self.attributes:
+                self.attributes[v] = self.attributes[str(i+1)]
+        # Override config and style attributes with attribute list attributes.
+        self.update_parameters(attrs)
+        check_array_parameter('options')
+        check_array_parameter('presubs')
+        check_array_parameter('postsubs')
+
+class AbstractBlocks:
+    """List of block definitions."""
+    PREFIX = ''         # Conf file section name prefix set in derived classes.
+    BLOCK_TYPE = None   # Block type set in derived classes.
+    def __init__(self):
+        self.current=None
+        self.blocks = []        # List of Block objects.
+        self.default = None     # Default Block.
+        self.delimiters = None  # Combined delimiters regular expression.
+    def load(self,sections):
+        """Load block definition from 'sections' dictionary."""
+        for k in sections.keys():
+            if re.match(r'^'+ self.PREFIX + r'.+$',k):
+                d = {}
+                parse_entries(sections.get(k,()),d)
+                for b in self.blocks:
+                    if b.name == k:
+                        break
+                else:
+                    b = self.BLOCK_TYPE()
+                    self.blocks.append(b)
+                try:
+                    b.load(k,d)
+                except EAsciiDoc,e:
+                    raise EAsciiDoc,'[%s] %s' % (k,str(e))
+    def dump(self):
+        for b in self.blocks:
+            b.dump()
+    def isnext(self):
+        for b in self.blocks:
+            if b.isnext():
+                self.current = b
+                return True;
+        return False
+    def validate(self):
+        """Validate the block definitions."""
+        # Validate delimiters and build combined lists delimiter pattern.
+        delimiters = []
+        for b in self.blocks:
+            assert b.__class__ is self.BLOCK_TYPE
+            b.validate()
+            if b.delimiter:
+                delimiters.append(b.delimiter)
+        self.delimiters = re_join(delimiters)
+
+class Paragraph(AbstractBlock):
+    def __init__(self):
+        AbstractBlock.__init__(self)
+        self.text=None          # Text in first line of paragraph.
+    def load(self,name,entries):
+        AbstractBlock.load(self,name,entries)
+    def dump(self):
+        AbstractBlock.dump(self)
+        write = lambda s: sys.stdout.write('%s%s' % (s,writer.newline))
+        write('')
+    def isnext(self):
+        result = AbstractBlock.isnext(self)
+        if result:
+            self.text = self.mo.groupdict().get('text')
+        return result
+    def translate(self):
+        AbstractBlock.translate(self)
+        attrs = self.mo.groupdict().copy()
+        if 'text' in attrs: del attrs['text']
+        BlockTitle.consume(attrs)
+        AttributeList.consume(attrs)
+        self.merge_attributes(attrs)
+        reader.read()   # Discard (already parsed item first line).
+        body = reader.read_until(paragraphs.terminators)
+        body = [self.text] + list(body)
+        presubs = self.parameters.presubs
+        postsubs = self.parameters.postsubs
+        if document.attributes.get('plaintext') is None:
+            body = Lex.set_margin(body) # Move body to left margin.
+        body = Lex.subs(body,presubs)
+        template = self.parameters.template
+        template = subs_attrs(template,attrs)
+        stag = config.section2tags(template, self.attributes,skipend=True)[0]
+        if self.parameters.filter:
+            body = filter_lines(self.parameters.filter,body,self.attributes)
+        body = Lex.subs(body,postsubs)
+        etag = config.section2tags(template, self.attributes,skipstart=True)[1]
+        # Write start tag, content, end tag.
+        writer.write(dovetail_tags(stag,body,etag),trace='paragraph')
+
+class Paragraphs(AbstractBlocks):
+    """List of paragraph definitions."""
+    BLOCK_TYPE = Paragraph
+    PREFIX = 'paradef-'
+    def __init__(self):
+        AbstractBlocks.__init__(self)
+        self.terminators=None    # List of compiled re's.
+    def initialize(self):
+        self.terminators = [
+                re.compile(r'^\+$|^$'),
+                re.compile(AttributeList.pattern),
+                re.compile(blocks.delimiters),
+                re.compile(tables.delimiters),
+                re.compile(tables_OLD.delimiters),
+            ]
+    def load(self,sections):
+        AbstractBlocks.load(self,sections)
+    def validate(self):
+        AbstractBlocks.validate(self)
+        # Check we have a default paragraph definition, put it last in list.
+        for b in self.blocks:
+            if b.name == 'paradef-default':
+                self.blocks.append(b)
+                self.default = b
+                self.blocks.remove(b)
+                break
+        else:
+            raise EAsciiDoc,'missing section: [paradef-default]'
+
+class List(AbstractBlock):
+    NUMBER_STYLES= ('arabic','loweralpha','upperalpha','lowerroman',
+                    'upperroman')
+    def __init__(self):
+        AbstractBlock.__init__(self)
+        self.CONF_ENTRIES += ('type','tags')
+        self.PARAM_NAMES += ('tags',)
+        # tabledef conf file parameters.
+        self.type=None
+        self.tags=None      # Name of listtags-<tags> conf section.
+        # Calculated parameters.
+        self.tag=None       # Current tags AttrDict.
+        self.label=None     # List item label (labeled lists).
+        self.text=None      # Text in first line of list item.
+        self.index=None     # Matched delimiter 'index' group (numbered lists).
+        self.type=None      # List type ('numbered','bulleted','labeled').
+        self.ordinal=None   # Current list item ordinal number (1..)
+        self.number_style=None # Current numbered list style ('arabic'..)
+    def load(self,name,entries):
+        AbstractBlock.load(self,name,entries)
+    def dump(self):
+        AbstractBlock.dump(self)
+        write = lambda s: sys.stdout.write('%s%s' % (s,writer.newline))
+        write('type='+self.type)
+        write('tags='+self.tags)
+        write('')
+    def validate(self):
+        AbstractBlock.validate(self)
+        tags = [self.tags]
+        tags += [s['tags'] for s in self.styles.values() if 'tags' in s]
+        for t in tags:
+            if t not in lists.tags:
+                self.error('missing section: [listtags-%s]' % t,halt=True)
+    def isnext(self):
+        result = AbstractBlock.isnext(self)
+        if result:
+            self.label = self.mo.groupdict().get('label')
+            self.text = self.mo.groupdict().get('text')
+            self.index = self.mo.groupdict().get('index')
+        return result
+    def translate_entry(self):
+        assert self.type == 'labeled'
+        entrytag = subs_tag(self.tag.entry, self.attributes)
+        labeltag = subs_tag(self.tag.label, self.attributes)
+        writer.write(entrytag[0],trace='list entry open')
+        writer.write(labeltag[0],trace='list label open')
+        # Write labels.
+        while Lex.next() is self:
+            reader.read()   # Discard (already parsed item first line).
+            writer.write_tag(self.tag.term, [self.label],
+                             self.presubs, self.attributes,trace='list term')
+            if self.text: break
+        writer.write(labeltag[1],trace='list label close')
+        # Write item text.
+        self.translate_item()
+        writer.write(entrytag[1],trace='list entry close')
+    def translate_item(self):
+        if self.type == 'callout':
+            self.attributes['coids'] = calloutmap.calloutids(self.ordinal)
+        itemtag = subs_tag(self.tag.item, self.attributes)
+        writer.write(itemtag[0],trace='list item open')
+        # Write ItemText.
+        text = reader.read_until(lists.terminators)
+        if self.text:
+            text = [self.text] + list(text)
+        if text:
+            writer.write_tag(self.tag.text, text, self.presubs, self.attributes,trace='list text')
+        # Process explicit and implicit list item continuations.
+        while True:
+            continuation = reader.read_next() == '+'
+            if continuation: reader.read()  # Discard continuation line.
+            while Lex.next() in (BlockTitle,AttributeList):
+                # Consume continued element title and attributes.
+                Lex.next().translate()
+            if not continuation and BlockTitle.title:
+                # Titled elements terminate the list.
+                break
+            next = Lex.next()
+            if next in lists.open:
+                break
+            elif isinstance(next,List):
+                next.translate()
+            elif isinstance(next,Paragraph) and 'listelement' in next.options:
+                next.translate()
+            elif continuation:
+                # This is where continued elements are processed.
+                if next is Title:
+                    message.error('section title not allowed in list item',halt=True)
+                next.translate()
+            else:
+                break
+        writer.write(itemtag[1],trace='list item close')
+
+    @staticmethod
+    def calc_style(index):
+        """Return the numbered list style ('arabic'...) of the list item index.
+        Return None if unrecognized style."""
+        if re.match(r'^\d+[\.>]$', index):
+            style = 'arabic'
+        elif re.match(r'^[ivx]+\)$', index):
+            style = 'lowerroman'
+        elif re.match(r'^[IVX]+\)$', index):
+            style = 'upperroman'
+        elif re.match(r'^[a-z]\.$', index):
+            style = 'loweralpha'
+        elif re.match(r'^[A-Z]\.$', index):
+            style = 'upperalpha'
+        else:
+            assert False
+        return style
+
+    @staticmethod
+    def calc_index(index,style):
+        """Return the ordinal number of (1...) of the list item index
+        for the given list style."""
+        def roman_to_int(roman):
+            roman = roman.lower()
+            digits = {'i':1,'v':5,'x':10}
+            result = 0
+            for i in range(len(roman)):
+                digit = digits[roman[i]]
+                # If next digit is larger this digit is negative.
+                if i+1 < len(roman) and digits[roman[i+1]] > digit:
+                    result -= digit
+                else:
+                    result += digit
+            return result
+        index = index[:-1]
+        if style == 'arabic':
+            ordinal = int(index)
+        elif style == 'lowerroman':
+            ordinal = roman_to_int(index)
+        elif style == 'upperroman':
+            ordinal = roman_to_int(index)
+        elif style == 'loweralpha':
+            ordinal = ord(index) - ord('a') + 1
+        elif style == 'upperalpha':
+            ordinal = ord(index) - ord('A') + 1
+        else:
+            assert False
+        return ordinal
+
+    def check_index(self):
+        """Check calculated self.ordinal (1,2,...) against the item number
+        in the document (self.index) and check the number style is the same as
+        the first item (self.number_style)."""
+        assert self.type in ('numbered','callout')
+        if self.index:
+            style = self.calc_style(self.index)
+            if style != self.number_style:
+                message.warning('list item style: expected %s got %s' %
+                        (self.number_style,style), offset=1)
+            ordinal = self.calc_index(self.index,style)
+            if ordinal != self.ordinal:
+                message.warning('list item index: expected %s got %s' %
+                        (self.ordinal,ordinal), offset=1)
+
+    def check_tags(self):
+        """ Check that all necessary tags are present. """
+        tags = set(Lists.TAGS)
+        if self.type != 'labeled':
+            tags = tags.difference(['entry','label','term'])
+        missing = tags.difference(self.tag.keys())
+        if missing:
+            self.error('missing tag(s): %s' % ','.join(missing), halt=True)
+    def translate(self):
+        AbstractBlock.translate(self)
+        if self.short_name() in ('bibliography','glossary','qanda'):
+            message.deprecated('old %s list syntax' % self.short_name())
+        lists.open.append(self)
+        attrs = self.mo.groupdict().copy()
+        for k in ('label','text','index'):
+            if k in attrs: del attrs[k]
+        if self.index:
+            # Set the numbering style from first list item.
+            attrs['style'] = self.calc_style(self.index)
+        BlockTitle.consume(attrs)
+        AttributeList.consume(attrs)
+        self.merge_attributes(attrs,['tags'])
+        if self.type in ('numbered','callout'):
+            self.number_style = self.attributes.get('style')
+            if self.number_style not in self.NUMBER_STYLES:
+                message.error('illegal numbered list style: %s' % self.number_style)
+                # Fall back to default style.
+                self.attributes['style'] = self.number_style = self.style
+        self.tag = lists.tags[self.parameters.tags]
+        self.check_tags()
+        if 'width' in self.attributes:
+            # Set horizontal list 'labelwidth' and 'itemwidth' attributes.
+            v = str(self.attributes['width'])
+            mo = re.match(r'^(\d{1,2})%?$',v)
+            if mo:
+                labelwidth = int(mo.group(1))
+                self.attributes['labelwidth'] = str(labelwidth)
+                self.attributes['itemwidth'] = str(100-labelwidth)
+            else:
+                self.error('illegal attribute value: width="%s"' % v)
+        stag,etag = subs_tag(self.tag.list, self.attributes)
+        if stag:
+            writer.write(stag,trace='list open')
+        self.ordinal = 0
+        # Process list till list syntax changes or there is a new title.
+        while Lex.next() is self and not BlockTitle.title:
+            self.ordinal += 1
+            document.attributes['listindex'] = str(self.ordinal)
+            if self.type in ('numbered','callout'):
+                self.check_index()
+            if self.type in ('bulleted','numbered','callout'):
+                reader.read()   # Discard (already parsed item first line).
+                self.translate_item()
+            elif self.type == 'labeled':
+                self.translate_entry()
+            else:
+                raise AssertionError,'illegal [%s] list type' % self.name
+        if etag:
+            writer.write(etag,trace='list close')
+        if self.type == 'callout':
+            calloutmap.validate(self.ordinal)
+            calloutmap.listclose()
+        lists.open.pop()
+        if len(lists.open):
+            document.attributes['listindex'] = str(lists.open[-1].ordinal)
+
+class Lists(AbstractBlocks):
+    """List of List objects."""
+    BLOCK_TYPE = List
+    PREFIX = 'listdef-'
+    TYPES = ('bulleted','numbered','labeled','callout')
+    TAGS = ('list', 'entry','item','text', 'label','term')
+    def __init__(self):
+        AbstractBlocks.__init__(self)
+        self.open = []  # A stack of the current and parent lists.
+        self.tags={}    # List tags dictionary. Each entry is a tags AttrDict.
+        self.terminators=None    # List of compiled re's.
+    def initialize(self):
+        self.terminators = [
+                re.compile(r'^\+$|^$'),
+                re.compile(AttributeList.pattern),
+                re.compile(lists.delimiters),
+                re.compile(blocks.delimiters),
+                re.compile(tables.delimiters),
+                re.compile(tables_OLD.delimiters),
+            ]
+    def load(self,sections):
+        AbstractBlocks.load(self,sections)
+        self.load_tags(sections)
+    def load_tags(self,sections):
+        """
+        Load listtags-* conf file sections to self.tags.
+        """
+        for section in sections.keys():
+            mo = re.match(r'^listtags-(?P<name>\w+)$',section)
+            if mo:
+                name = mo.group('name')
+                if name in self.tags:
+                    d = self.tags[name]
+                else:
+                    d = AttrDict()
+                parse_entries(sections.get(section,()),d)
+                for k in d.keys():
+                    if k not in self.TAGS:
+                        message.warning('[%s] contains illegal list tag: %s' %
+                                (section,k))
+                self.tags[name] = d
+    def validate(self):
+        AbstractBlocks.validate(self)
+        for b in self.blocks:
+            # Check list has valid type.
+            if not b.type in Lists.TYPES:
+                raise EAsciiDoc,'[%s] illegal type' % b.name
+            b.validate()
+    def dump(self):
+        AbstractBlocks.dump(self)
+        for k,v in self.tags.items():
+            dump_section('listtags-'+k, v)
+
+
+class DelimitedBlock(AbstractBlock):
+    def __init__(self):
+        AbstractBlock.__init__(self)
+    def load(self,name,entries):
+        AbstractBlock.load(self,name,entries)
+    def dump(self):
+        AbstractBlock.dump(self)
+        write = lambda s: sys.stdout.write('%s%s' % (s,writer.newline))
+        write('')
+    def isnext(self):
+        return AbstractBlock.isnext(self)
+    def translate(self):
+        AbstractBlock.translate(self)
+        reader.read()   # Discard delimiter.
+        attrs = {}
+        if self.short_name() != 'comment':
+            BlockTitle.consume(attrs)
+            AttributeList.consume(attrs)
+        self.merge_attributes(attrs)
+        options = self.parameters.options
+        if 'skip' in options:
+            reader.read_until(self.delimiter,same_file=True)
+        elif safe() and self.name == 'blockdef-backend':
+            message.unsafe('Backend Block')
+            reader.read_until(self.delimiter,same_file=True)
+        else:
+            template = self.parameters.template
+            template = subs_attrs(template,attrs)
+            name = self.short_name()+' block'
+            if 'sectionbody' in options:
+                # The body is treated like a section body.
+                stag,etag = config.section2tags(template,self.attributes)
+                writer.write(stag,trace=name+' open')
+                Section.translate_body(self)
+                writer.write(etag,trace=name+' close')
+            else:
+                stag = config.section2tags(template,self.attributes,skipend=True)[0]
+                body = reader.read_until(self.delimiter,same_file=True)
+                presubs = self.parameters.presubs
+                postsubs = self.parameters.postsubs
+                body = Lex.subs(body,presubs)
+                if self.parameters.filter:
+                    body = filter_lines(self.parameters.filter,body,self.attributes)
+                body = Lex.subs(body,postsubs)
+                # Write start tag, content, end tag.
+                etag = config.section2tags(template,self.attributes,skipstart=True)[1]
+                writer.write(dovetail_tags(stag,body,etag),trace=name)
+            trace(self.short_name()+' block close',etag)
+        if reader.eof():
+            self.error('missing closing delimiter',self.start)
+        else:
+            delimiter = reader.read()   # Discard delimiter line.
+            assert re.match(self.delimiter,delimiter)
+
+class DelimitedBlocks(AbstractBlocks):
+    """List of delimited blocks."""
+    BLOCK_TYPE = DelimitedBlock
+    PREFIX = 'blockdef-'
+    def __init__(self):
+        AbstractBlocks.__init__(self)
+    def load(self,sections):
+        """Update blocks defined in 'sections' dictionary."""
+        AbstractBlocks.load(self,sections)
+    def validate(self):
+        AbstractBlocks.validate(self)
+
+class Column:
+    """Table column."""
+    def __init__(self, width=None, align_spec=None, style=None):
+        self.width = width or '1'
+        self.halign, self.valign = Table.parse_align_spec(align_spec)
+        self.style = style      # Style name or None.
+        # Calculated attribute values.
+        self.abswidth = None    # 1..   (page units).
+        self.pcwidth = None     # 1..99 (percentage).
+
+class Cell:
+    def __init__(self, data, span_spec=None, align_spec=None, style=None):
+        self.data = data
+        self.span, self.vspan = Table.parse_span_spec(span_spec)
+        self.halign, self.valign = Table.parse_align_spec(align_spec)
+        self.style = style
+    def __repr__(self):
+        return '<Cell: %d.%d %s.%s %s "%s">' % (
+                self.span, self.vspan,
+                self.halign, self.valign,
+                self.style or '',
+                self.data)
+
+class Table(AbstractBlock):
+    ALIGN = {'<':'left', '>':'right', '^':'center'}
+    VALIGN = {'<':'top', '>':'bottom', '^':'middle'}
+    FORMATS = ('psv','csv','dsv')
+    SEPARATORS = dict(
+        csv=',',
+        dsv=r':|\n',
+        # The count and align group matches are not exact.
+        psv=r'((?<!\S)((?P<span>[\d.]+)(?P<op>[*+]))?(?P<align>[<\^>.]{,3})?(?P<style>[a-z])?)?\|'
+    )
+    def __init__(self):
+        AbstractBlock.__init__(self)
+        self.CONF_ENTRIES += ('format','tags','separator')
+        # tabledef conf file parameters.
+        self.format='psv'
+        self.separator=None
+        self.tags=None          # Name of tabletags-<tags> conf section.
+        # Calculated parameters.
+        self.abswidth=None      # 1..   (page units).
+        self.pcwidth = None     # 1..99 (percentage).
+        self.rows=[]            # Parsed rows, each row is a list of Cells.
+        self.columns=[]         # List of Columns.
+    @staticmethod
+    def parse_align_spec(align_spec):
+        """
+        Parse AsciiDoc cell alignment specifier and return 2-tuple with
+        horizonatal and vertical alignment names. Unspecified alignments
+        set to None.
+        """
+        result = (None, None)
+        if align_spec:
+            mo = re.match(r'^([<\^>])?(\.([<\^>]))?$', align_spec)
+            if mo:
+                result = (Table.ALIGN.get(mo.group(1)),
+                          Table.VALIGN.get(mo.group(3)))
+        return result
+    @staticmethod
+    def parse_span_spec(span_spec):
+        """
+        Parse AsciiDoc cell span specifier and return 2-tuple with horizonatal
+        and vertical span counts. Set default values (1,1) if not
+        specified.
+        """
+        result = (None, None)
+        if span_spec:
+            mo = re.match(r'^(\d+)?(\.(\d+))?$', span_spec)
+            if mo:
+                result = (mo.group(1) and int(mo.group(1)),
+                          mo.group(3) and int(mo.group(3)))
+        return (result[0] or 1, result[1] or 1)
+    def load(self,name,entries):
+        AbstractBlock.load(self,name,entries)
+    def dump(self):
+        AbstractBlock.dump(self)
+        write = lambda s: sys.stdout.write('%s%s' % (s,writer.newline))
+        write('format='+self.format)
+        write('')
+    def validate(self):
+        AbstractBlock.validate(self)
+        if self.format not in Table.FORMATS:
+            self.error('illegal format=%s' % self.format,halt=True)
+        self.tags = self.tags or 'default'
+        tags = [self.tags]
+        tags += [s['tags'] for s in self.styles.values() if 'tags' in s]
+        for t in tags:
+            if t not in tables.tags:
+                self.error('missing section: [tabletags-%s]' % t,halt=True)
+        if self.separator:
+            # Evaluate escape characters.
+            self.separator = eval('"'+self.separator+'"')
+        #TODO: Move to class Tables
+        # Check global table parameters.
+        elif config.pagewidth is None:
+            self.error('missing [miscellaneous] entry: pagewidth')
+        elif config.pageunits is None:
+            self.error('missing [miscellaneous] entry: pageunits')
+    def validate_attributes(self):
+        """Validate and parse table attributes."""
+        # Set defaults.
+        format = self.format
+        tags = self.tags
+        separator = self.separator
+        abswidth = float(config.pagewidth)
+        pcwidth = 100.0
+        for k,v in self.attributes.items():
+            if k == 'format':
+                if v not in self.FORMATS:
+                    self.error('illegal %s=%s' % (k,v))
+                else:
+                    format = v
+            elif k == 'tags':
+                if v not in tables.tags:
+                    self.error('illegal %s=%s' % (k,v))
+                else:
+                    tags = v
+            elif k == 'separator':
+                separator = v
+            elif k == 'width':
+                if not re.match(r'^\d{1,3}%$',v) or int(v[:-1]) > 100:
+                    self.error('illegal %s=%s' % (k,v))
+                else:
+                    abswidth = float(v[:-1])/100 * config.pagewidth
+                    pcwidth = float(v[:-1])
+        # Calculate separator if it has not been specified.
+        if not separator:
+            separator = Table.SEPARATORS[format]
+        if format == 'csv':
+            if len(separator) > 1:
+                self.error('illegal csv separator=%s' % separator)
+                separator = ','
+        else:
+            if not is_re(separator):
+                self.error('illegal regular expression: separator=%s' %
+                        separator)
+        self.parameters.format = format
+        self.parameters.tags = tags
+        self.parameters.separator = separator
+        self.abswidth = abswidth
+        self.pcwidth = pcwidth
+    def get_tags(self,params):
+        tags = self.get_param('tags',params)
+        assert(tags and tags in tables.tags)
+        return tables.tags[tags]
+    def get_style(self,prefix):
+        """
+        Return the style dictionary whose name starts with 'prefix'.
+        """
+        if prefix is None:
+            return None
+        names = self.styles.keys()
+        names.sort()
+        for name in names:
+            if name.startswith(prefix):
+                return self.styles[name]
+        else:
+            self.error('missing style: %s*' % prefix)
+            return None
+    def parse_cols(self, cols, halign, valign):
+        """
+        Build list of column objects from table 'cols', 'halign' and 'valign'
+        attributes.
+        """
+        # [<multiplier>*][<align>][<width>][<style>]
+        COLS_RE1 = r'^((?P<count>\d+)\*)?(?P<align>[<\^>.]{,3})?(?P<width>\d+%?)?(?P<style>[a-z]\w*)?$'
+        # [<multiplier>*][<width>][<align>][<style>]
+        COLS_RE2 = r'^((?P<count>\d+)\*)?(?P<width>\d+%?)?(?P<align>[<\^>.]{,3})?(?P<style>[a-z]\w*)?$'
+        reo1 = re.compile(COLS_RE1)
+        reo2 = re.compile(COLS_RE2)
+        cols = str(cols)
+        if re.match(r'^\d+$',cols):
+            for i in range(int(cols)):
+                self.columns.append(Column())
+        else:
+            for col in re.split(r'\s*,\s*',cols):
+                mo = reo1.match(col)
+                if not mo:
+                    mo = reo2.match(col)
+                if mo:
+                    count = int(mo.groupdict().get('count') or 1)
+                    for i in range(count):
+                        self.columns.append(
+                            Column(mo.group('width'), mo.group('align'),
+                                   self.get_style(mo.group('style')))
+                        )
+                else:
+                    self.error('illegal column spec: %s' % col,self.start)
+        # Set column (and indirectly cell) default alignments.
+        for col in self.columns:
+            col.halign = col.halign or halign or document.attributes.get('halign') or 'left'
+            col.valign = col.valign or valign or document.attributes.get('valign') or 'top'
+        # Validate widths and calculate missing widths.
+        n = 0; percents = 0; props = 0
+        for col in self.columns:
+            if col.width:
+                if col.width[-1] == '%': percents += int(col.width[:-1])
+                else: props += int(col.width)
+                n += 1
+        if percents > 0 and props > 0:
+            self.error('mixed percent and proportional widths: %s'
+                    % cols,self.start)
+        pcunits = percents > 0
+        # Fill in missing widths.
+        if n < len(self.columns) and percents < 100:
+            if pcunits:
+                width = float(100 - percents)/float(len(self.columns) - n)
+            else:
+                width = 1
+            for col in self.columns:
+                if not col.width:
+                    if pcunits:
+                        col.width = str(int(width))+'%'
+                        percents += width
+                    else:
+                        col.width = str(width)
+                        props += width
+        # Calculate column alignment and absolute and percent width values.
+        percents = 0
+        for col in self.columns:
+            if pcunits:
+                col.pcwidth = float(col.width[:-1])
+            else:
+                col.pcwidth = (float(col.width)/props)*100
+            col.abswidth = self.abswidth * (col.pcwidth/100)
+            if config.pageunits in ('cm','mm','in','em'):
+                col.abswidth = '%.2f' % round(col.abswidth,2)
+            else:
+                col.abswidth = '%d' % round(col.abswidth)
+            percents += col.pcwidth
+            col.pcwidth = int(col.pcwidth)
+        if round(percents) > 100:
+            self.error('total width exceeds 100%%: %s' % cols,self.start)
+        elif round(percents) < 100:
+            self.error('total width less than 100%%: %s' % cols,self.start)
+    def build_colspecs(self):
+        """
+        Generate column related substitution attributes.
+        """
+        cols = []
+        i = 1
+        for col in self.columns:
+            colspec = self.get_tags(col.style).colspec
+            if colspec:
+                self.attributes['halign'] = col.halign
+                self.attributes['valign'] = col.valign
+                self.attributes['colabswidth'] = col.abswidth
+                self.attributes['colpcwidth'] = col.pcwidth
+                self.attributes['colnumber'] = str(i)
+                s = subs_attrs(colspec, self.attributes)
+                if not s:
+                    message.warning('colspec dropped: contains undefined attribute')
+                else:
+                    cols.append(s)
+            i += 1
+        if cols:
+            self.attributes['colspecs'] = writer.newline.join(cols)
+    def parse_rows(self, text):
+        """
+        Parse the table source text into self.rows (a list of rows, each row
+        is a list of Cells.
+        """
+        reserved = {}  # Cols reserved by rowspans (indexed by row number).
+        if self.parameters.format in ('psv','dsv'):
+            ri = 0  # Current row index 0..
+            cells = self.parse_psv_dsv(text)
+            row = []
+            ci = 0  # Column counter 0..colcount
+            for cell in cells:
+                colcount = len(self.columns) - reserved.get(ri,0)
+                if cell.vspan > 1:
+                    # Reserve spanned columns from ensuing rows.
+                    for i in range(1, cell.vspan):
+                        reserved[ri+i] = reserved.get(ri+i, 0) + cell.span
+                ci += cell.span
+                if ci <= colcount:
+                    row.append(cell)
+                if ci >= colcount:
+                    self.rows.append(row)
+                    ri += 1
+                    row = []
+                    ci = 0
+                if ci > colcount:
+                    message.warning('table row %d: span exceeds number of columns'
+                            % ri)
+        elif self.parameters.format == 'csv':
+            self.rows = self.parse_csv(text)
+        else:
+            assert True,'illegal table format'
+        # Check that all row spans match.
+        for ri,row in enumerate(self.rows):
+            row_span = 0
+            for cell in row:
+                row_span += cell.span
+            row_span += reserved.get(ri,0)
+            if ri == 0:
+                header_span = row_span
+            if row_span < header_span:
+                message.warning('table row %d: does not span all columns' % (ri+1))
+            if row_span > header_span:
+                message.warning('table row %d: exceeds columns span' % (ri+1))
+        # Check that now row spans exceed the number of rows.
+        if len([x for x in reserved.keys() if x >= len(self.rows)]) > 0:
+            message.warning('one or more cell spans exceed the available rows')
+    def subs_rows(self, rows, rowtype='body'):
+        """
+        Return a string of output markup from a list of rows, each row
+        is a list of raw data text.
+        """
+        tags = tables.tags[self.parameters.tags]
+        if rowtype == 'header':
+            rtag = tags.headrow
+        elif rowtype == 'footer':
+            rtag = tags.footrow
+        else:
+            rtag = tags.bodyrow
+        result = []
+        stag,etag = subs_tag(rtag,self.attributes)
+        for row in rows:
+            result.append(stag)
+            result += self.subs_row(row,rowtype)
+            result.append(etag)
+        return writer.newline.join(result)
+    def subs_row(self, row, rowtype):
+        """
+        Substitute the list of Cells using the data tag.
+        Returns a list of marked up table cell elements.
+        """
+        result = []
+        i = 0
+        for cell in row:
+            if i >= len(self.columns):
+                break   # Skip cells outside the header width.
+            col = self.columns[i]
+            self.attributes['halign'] = cell.halign or col.halign
+            self.attributes['valign'] = cell.valign or  col.valign
+            self.attributes['colabswidth'] = col.abswidth
+            self.attributes['colpcwidth'] = col.pcwidth
+            self.attributes['colnumber'] = str(i+1)
+            self.attributes['colspan'] = str(cell.span)
+            self.attributes['colstart'] = self.attributes['colnumber']
+            self.attributes['colend'] = str(i+cell.span)
+            self.attributes['rowspan'] = str(cell.vspan)
+            self.attributes['morerows'] = str(cell.vspan-1)
+            # Fill missing column data with blanks.
+            if i > len(self.columns) - 1:
+                data = ''
+            else:
+                data = cell.data
+            if rowtype == 'header':
+                # Use table style unless overriden by cell style.
+                colstyle = cell.style
+            else:
+                # If the cell style is not defined use the column style.
+                colstyle = cell.style or col.style
+            tags = self.get_tags(colstyle)
+            presubs,postsubs = self.get_subs(colstyle)
+            data = [data]
+            data = Lex.subs(data, presubs)
+            data = filter_lines(self.get_param('filter',colstyle),
+                                data, self.attributes)
+            data = Lex.subs(data, postsubs)
+            if rowtype != 'header':
+                ptag = tags.paragraph
+                if ptag:
+                    stag,etag = subs_tag(ptag,self.attributes)
+                    text = '\n'.join(data).strip()
+                    data = []
+                    for para in re.split(r'\n{2,}',text):
+                        data += dovetail_tags([stag],para.split('\n'),[etag])
+            if rowtype == 'header':
+                dtag = tags.headdata
+            elif rowtype == 'footer':
+                dtag = tags.footdata
+            else:
+                dtag = tags.bodydata
+            stag,etag = subs_tag(dtag,self.attributes)
+            result = result + dovetail_tags([stag],data,[etag])
+            i += cell.span
+        return result
+    def parse_csv(self,text):
+        """
+        Parse the table source text and return a list of rows, each row
+        is a list of Cells.
+        """
+        import StringIO
+        import csv
+        rows = []
+        rdr = csv.reader(StringIO.StringIO('\r\n'.join(text)),
+                     delimiter=self.parameters.separator, skipinitialspace=True)
+        try:
+            for row in rdr:
+                rows.append([Cell(data) for data in row])
+        except Exception:
+            self.error('csv parse error: %s' % row)
+        return rows
+    def parse_psv_dsv(self,text):
+        """
+        Parse list of PSV or DSV table source text lines and return a list of
+        Cells.
+        """
+        def append_cell(data, span_spec, op, align_spec, style):
+            op = op or '+'
+            if op == '*':   # Cell multiplier.
+                span = Table.parse_span_spec(span_spec)[0]
+                for i in range(span):
+                    cells.append(Cell(data, '1', align_spec, style))
+            elif op == '+': # Column spanner.
+                cells.append(Cell(data, span_spec, align_spec, style))
+            else:
+                self.error('illegal table cell operator')
+        text = '\n'.join(text)
+        separator = '(?msu)'+self.parameters.separator
+        format = self.parameters.format
+        start = 0
+        span = None
+        op = None
+        align = None
+        style = None
+        cells = []
+        data = ''
+        for mo in re.finditer(separator,text):
+            data += text[start:mo.start()]
+            if data.endswith('\\'):
+                data = data[:-1]+mo.group() # Reinstate escaped separators.
+            else:
+                append_cell(data, span, op, align, style)
+                span = mo.groupdict().get('span')
+                op = mo.groupdict().get('op')
+                align = mo.groupdict().get('align')
+                style = mo.groupdict().get('style')
+                if style:
+                    style = self.get_style(style)
+                data = ''
+            start = mo.end()
+        # Last cell follows final separator.
+        data += text[start:]
+        append_cell(data, span, op, align, style)
+        # We expect a dummy blank item preceeding first PSV cell.
+        if format == 'psv':
+            if cells[0].data.strip() != '':
+                self.error('missing leading separator: %s' % separator,
+                        self.start)
+            else:
+                cells.pop(0)
+        return cells
+    def translate(self):
+        AbstractBlock.translate(self)
+        reader.read()   # Discard delimiter.
+        # Reset instance specific properties.
+        self.columns = []
+        self.rows = []
+        attrs = {}
+        BlockTitle.consume(attrs)
+        # Mix in document attribute list.
+        AttributeList.consume(attrs)
+        self.merge_attributes(attrs)
+        self.validate_attributes()
+        # Add global and calculated configuration parameters.
+        self.attributes['pagewidth'] = config.pagewidth
+        self.attributes['pageunits'] = config.pageunits
+        self.attributes['tableabswidth'] = int(self.abswidth)
+        self.attributes['tablepcwidth'] = int(self.pcwidth)
+        # Read the entire table.
+        text = reader.read_until(self.delimiter)
+        if reader.eof():
+            self.error('missing closing delimiter',self.start)
+        else:
+            delimiter = reader.read()   # Discard closing delimiter.
+            assert re.match(self.delimiter,delimiter)
+        if len(text) == 0:
+            message.warning('[%s] table is empty' % self.name)
+            return
+        cols = attrs.get('cols')
+        if not cols:
+            # Calculate column count from number of items in first line.
+            if self.parameters.format == 'csv':
+                cols = text[0].count(self.parameters.separator) + 1
+            else:
+                cols = 0
+                for cell in self.parse_psv_dsv(text[:1]):
+                    cols += cell.span
+        self.parse_cols(cols, attrs.get('halign'), attrs.get('valign'))
+        # Set calculated attributes.
+        self.attributes['colcount'] = len(self.columns)
+        self.build_colspecs()
+        self.parse_rows(text)
+        # The 'rowcount' attribute is used by the experimental LaTeX backend.
+        self.attributes['rowcount'] = str(len(self.rows))
+        # Generate headrows, footrows, bodyrows.
+        # Headrow, footrow and bodyrow data replaces same named attributes in
+        # the table markup template. In order to ensure this data does not get
+        # a second attribute substitution (which would interfere with any
+        # already substituted inline passthroughs) unique placeholders are used
+        # (the tab character does not appear elsewhere since it is expanded on
+        # input) which are replaced after template attribute substitution.
+        headrows = footrows = bodyrows = None
+        if self.rows and 'header' in self.parameters.options:
+            headrows = self.subs_rows(self.rows[0:1],'header')
+            self.attributes['headrows'] = '\x07headrows\x07'
+            self.rows = self.rows[1:]
+        if self.rows and 'footer' in self.parameters.options:
+            footrows = self.subs_rows( self.rows[-1:], 'footer')
+            self.attributes['footrows'] = '\x07footrows\x07'
+            self.rows = self.rows[:-1]
+        if self.rows:
+            bodyrows = self.subs_rows(self.rows)
+            self.attributes['bodyrows'] = '\x07bodyrows\x07'
+        table = subs_attrs(config.sections[self.parameters.template],
+                           self.attributes)
+        table = writer.newline.join(table)
+        # Before we finish replace the table head, foot and body place holders
+        # with the real data.
+        if headrows:
+            table = table.replace('\x07headrows\x07', headrows, 1)
+        if footrows:
+            table = table.replace('\x07footrows\x07', footrows, 1)
+        if bodyrows:
+            table = table.replace('\x07bodyrows\x07', bodyrows, 1)
+        writer.write(table,trace='table')
+
+class Tables(AbstractBlocks):
+    """List of tables."""
+    BLOCK_TYPE = Table
+    PREFIX = 'tabledef-'
+    TAGS = ('colspec', 'headrow','footrow','bodyrow',
+            'headdata','footdata', 'bodydata','paragraph')
+    def __init__(self):
+        AbstractBlocks.__init__(self)
+        # Table tags dictionary. Each entry is a tags dictionary.
+        self.tags={}
+    def load(self,sections):
+        AbstractBlocks.load(self,sections)
+        self.load_tags(sections)
+    def load_tags(self,sections):
+        """
+        Load tabletags-* conf file sections to self.tags.
+        """
+        for section in sections.keys():
+            mo = re.match(r'^tabletags-(?P<name>\w+)$',section)
+            if mo:
+                name = mo.group('name')
+                if name in self.tags:
+                    d = self.tags[name]
+                else:
+                    d = AttrDict()
+                parse_entries(sections.get(section,()),d)
+                for k in d.keys():
+                    if k not in self.TAGS:
+                        message.warning('[%s] contains illegal table tag: %s' %
+                                (section,k))
+                self.tags[name] = d
+    def validate(self):
+        AbstractBlocks.validate(self)
+        # Check we have a default table definition,
+        for i in range(len(self.blocks)):
+            if self.blocks[i].name == 'tabledef-default':
+                default = self.blocks[i]
+                break
+        else:
+            raise EAsciiDoc,'missing section: [tabledef-default]'
+        # Propagate defaults to unspecified table parameters.
+        for b in self.blocks:
+            if b is not default:
+                if b.format is None: b.format = default.format
+                if b.template is None: b.template = default.template
+        # Check tags and propagate default tags.
+        if not 'default' in self.tags:
+            raise EAsciiDoc,'missing section: [tabletags-default]'
+        default = self.tags['default']
+        for tag in ('bodyrow','bodydata','paragraph'): # Mandatory default tags.
+            if tag not in default:
+                raise EAsciiDoc,'missing [tabletags-default] entry: %s' % tag
+        for t in self.tags.values():
+            if t is not default:
+                if t.colspec is None: t.colspec = default.colspec
+                if t.headrow is None: t.headrow = default.headrow
+                if t.footrow is None: t.footrow = default.footrow
+                if t.bodyrow is None: t.bodyrow = default.bodyrow
+                if t.headdata is None: t.headdata = default.headdata
+                if t.footdata is None: t.footdata = default.footdata
+                if t.bodydata is None: t.bodydata = default.bodydata
+                if t.paragraph is None: t.paragraph = default.paragraph
+        # Use body tags if header and footer tags are not specified.
+        for t in self.tags.values():
+            if not t.headrow: t.headrow = t.bodyrow
+            if not t.footrow: t.footrow = t.bodyrow
+            if not t.headdata: t.headdata = t.bodydata
+            if not t.footdata: t.footdata = t.bodydata
+        # Check table definitions are valid.
+        for b in self.blocks:
+            b.validate()
+    def dump(self):
+        AbstractBlocks.dump(self)
+        for k,v in self.tags.items():
+            dump_section('tabletags-'+k, v)
+
+class Macros:
+    # Default system macro syntax.
+    SYS_RE = r'(?u)^(?P<name>[\\]?\w(\w|-)*?)::(?P<target>\S*?)' + \
+             r'(\[(?P<attrlist>.*?)\])$'
+    def __init__(self):
+        self.macros = []        # List of Macros.
+        self.current = None     # The last matched block macro.
+        self.passthroughs = []
+        # Initialize default system macro.
+        m = Macro()
+        m.pattern = self.SYS_RE
+        m.prefix = '+'
+        m.reo = re.compile(m.pattern)
+        self.macros.append(m)
+    def load(self,entries):
+        for entry in entries:
+            m = Macro()
+            m.load(entry)
+            if m.name is None:
+                # Delete undefined macro.
+                for i,m2 in enumerate(self.macros):
+                    if m2.pattern == m.pattern:
+                        del self.macros[i]
+                        break
+                else:
+                    message.warning('unable to delete missing macro: %s' % m.pattern)
+            else:
+                # Check for duplicates.
+                for m2 in self.macros:
+                    if m2.pattern == m.pattern:
+                        message.verbose('macro redefinition: %s%s' % (m.prefix,m.name))
+                        break
+                else:
+                    self.macros.append(m)
+    def dump(self):
+        write = lambda s: sys.stdout.write('%s%s' % (s,writer.newline))
+        write('[macros]')
+        # Dump all macros except the first (built-in system) macro.
+        for m in self.macros[1:]:
+            # Escape = in pattern.
+            macro = '%s=%s%s' % (m.pattern.replace('=',r'\='), m.prefix, m.name)
+            if m.subslist is not None:
+                macro += '[' + ','.join(m.subslist) + ']'
+            write(macro)
+        write('')
+    def validate(self):
+        # Check all named sections exist.
+        if config.verbose:
+            for m in self.macros:
+                if m.name and m.prefix != '+':
+                    m.section_name()
+    def subs(self,text,prefix='',callouts=False):
+        # If callouts is True then only callout macros are processed, if False
+        # then all non-callout macros are processed.
+        result = text
+        for m in self.macros:
+            if m.prefix == prefix:
+                if callouts ^ (m.name != 'callout'):
+                    result = m.subs(result)
+        return result
+    def isnext(self):
+        """Return matching macro if block macro is next on reader."""
+        reader.skip_blank_lines()
+        line = reader.read_next()
+        if line:
+            for m in self.macros:
+                if m.prefix == '#':
+                    if m.reo.match(line):
+                        self.current = m
+                        return m
+        return False
+    def match(self,prefix,name,text):
+        """Return re match object matching 'text' with macro type 'prefix',
+        macro name 'name'."""
+        for m in self.macros:
+            if m.prefix == prefix:
+                mo = m.reo.match(text)
+                if mo:
+                    if m.name == name:
+                        return mo
+                    if re.match(name,mo.group('name')):
+                        return mo
+        return None
+    def extract_passthroughs(self,text,prefix=''):
+        """ Extract the passthrough text and replace with temporary
+        placeholders."""
+        self.passthroughs = []
+        for m in self.macros:
+            if m.has_passthrough() and m.prefix == prefix:
+                text = m.subs_passthroughs(text, self.passthroughs)
+        return text
+    def restore_passthroughs(self,text):
+        """ Replace passthough placeholders with the original passthrough
+        text."""
+        for i,v in enumerate(self.passthroughs):
+            text = text.replace('\x07'+str(i)+'\x07', self.passthroughs[i])
+        return text
+
+class Macro:
+    def __init__(self):
+        self.pattern = None     # Matching regular expression.
+        self.name = ''          # Conf file macro name (None if implicit).
+        self.prefix = ''        # '' if inline, '+' if system, '#' if block.
+        self.reo = None         # Compiled pattern re object.
+        self.subslist = []      # Default subs for macros passtext group.
+    def has_passthrough(self):
+        return self.pattern.find(r'(?P<passtext>') >= 0
+    def section_name(self,name=None):
+        """Return macro markup template section name based on macro name and
+        prefix.  Return None section not found."""
+        assert self.prefix != '+'
+        if not name:
+            assert self.name
+            name = self.name
+        if self.prefix == '#':
+            suffix = '-blockmacro'
+        else:
+            suffix = '-inlinemacro'
+        if name+suffix in config.sections:
+            return name+suffix
+        else:
+            message.warning('missing macro section: [%s]' % (name+suffix))
+            return None
+    def load(self,entry):
+        e = parse_entry(entry)
+        if e is None:
+            # Only the macro pattern was specified, mark for deletion.
+            self.name = None
+            self.pattern = entry
+            return
+        if not is_re(e[0]):
+            raise EAsciiDoc,'illegal macro regular expression: %s' % e[0]
+        pattern, name = e
+        if name and name[0] in ('+','#'):
+            prefix, name = name[0], name[1:]
+        else:
+            prefix = ''
+        # Parse passthrough subslist.
+        mo = re.match(r'^(?P<name>[^[]*)(\[(?P<subslist>.*)\])?$', name)
+        name = mo.group('name')
+        if name and not is_name(name):
+            raise EAsciiDoc,'illegal section name in macro entry: %s' % entry
+        subslist = mo.group('subslist')
+        if subslist is not None:
+            # Parse and validate passthrough subs.
+            subslist = parse_options(subslist, SUBS_OPTIONS,
+                                 'illegal subs in macro entry: %s' % entry)
+        self.pattern = pattern
+        self.reo = re.compile(pattern)
+        self.prefix = prefix
+        self.name = name
+        self.subslist = subslist or []
+
+    def subs(self,text):
+        def subs_func(mo):
+            """Function called to perform macro substitution.
+            Uses matched macro regular expression object and returns string
+            containing the substituted macro body."""
+            # Check if macro reference is escaped.
+            if mo.group()[0] == '\\':
+                return mo.group()[1:]   # Strip leading backslash.
+            d = mo.groupdict()
+            # Delete groups that didn't participate in match.
+            for k,v in d.items():
+                if v is None: del d[k]
+            if self.name:
+                name = self.name
+            else:
+                if not 'name' in d:
+                    message.warning('missing macro name group: %s' % mo.re.pattern)
+                    return ''
+                name = d['name']
+            section_name = self.section_name(name)
+            if not section_name:
+                return ''
+            # If we're dealing with a block macro get optional block ID and
+            # block title.
+            if self.prefix == '#' and self.name != 'comment':
+                AttributeList.consume(d)
+                BlockTitle.consume(d)
+            # Parse macro attributes.
+            if 'attrlist' in d:
+                if d['attrlist'] in (None,''):
+                    del d['attrlist']
+                else:
+                    if self.prefix == '':
+                        # Unescape ] characters in inline macros.
+                        d['attrlist'] = d['attrlist'].replace('\\]',']')
+                    parse_attributes(d['attrlist'],d)
+                    # Generate option attributes.
+                    if 'options' in d:
+                        options = parse_options(d['options'], (),
+                                '%s: illegal option name' % name)
+                        for option in options:
+                            d[option+'-option'] = ''
+                    # Substitute single quoted attribute values in block macros.
+                    if self.prefix == '#':
+                        AttributeList.subs(d)
+            if name == 'callout':
+                listindex =int(d['index'])
+                d['coid'] = calloutmap.add(listindex)
+            # The alt attribute is the first image macro positional attribute.
+            if name == 'image' and '1' in d:
+                d['alt'] = d['1']
+            # Unescape special characters in LaTeX target file names.
+            if document.backend == 'latex' and 'target' in d and d['target']:
+                if not '0' in d:
+                    d['0'] = d['target']
+                d['target']= config.subs_specialchars_reverse(d['target'])
+            # BUG: We've already done attribute substitution on the macro which
+            # means that any escaped attribute references are now unescaped and
+            # will be substituted by config.subs_section() below. As a partial
+            # fix have withheld {0} from substitution but this kludge doesn't
+            # fix it for other attributes containing unescaped references.
+            # Passthrough macros don't have this problem.
+            a0 = d.get('0')
+            if a0:
+                d['0'] = chr(0)  # Replace temporarily with unused character.
+            body = config.subs_section(section_name,d)
+            if len(body) == 0:
+                result = ''
+            elif len(body) == 1:
+                result = body[0]
+            else:
+                if self.prefix == '#':
+                    result = writer.newline.join(body)
+                else:
+                    # Internally processed inline macros use UNIX line
+                    # separator.
+                    result = '\n'.join(body)
+            if a0:
+                result = result.replace(chr(0), a0)
+            return result
+
+        return self.reo.sub(subs_func, text)
+
+    def translate(self):
+        """ Block macro translation."""
+        assert self.prefix == '#'
+        s = reader.read()
+        before = s
+        if self.has_passthrough():
+            s = macros.extract_passthroughs(s,'#')
+        s = subs_attrs(s)
+        if s:
+            s = self.subs(s)
+            if self.has_passthrough():
+                s = macros.restore_passthroughs(s)
+            if s:
+                trace('macro block',before,s)
+                writer.write(s)
+
+    def subs_passthroughs(self, text, passthroughs):
+        """ Replace macro attribute lists in text with placeholders.
+        Substitute and append the passthrough attribute lists to the
+        passthroughs list."""
+        def subs_func(mo):
+            """Function called to perform inline macro substitution.
+            Uses matched macro regular expression object and returns string
+            containing the substituted macro body."""
+            # Don't process escaped macro references.
+            if mo.group()[0] == '\\':
+                return mo.group()
+            d = mo.groupdict()
+            if not 'passtext' in d:
+                message.warning('passthrough macro %s: missing passtext group' %
+                        d.get('name',''))
+                return mo.group()
+            passtext = d['passtext']
+            if re.search('\x07\\d+\x07', passtext):
+                message.warning('nested inline passthrough')
+                return mo.group()
+            if d.get('subslist'):
+                if d['subslist'].startswith(':'):
+                    message.error('block macro cannot occur here: %s' % mo.group(),
+                          halt=True)
+                subslist = parse_options(d['subslist'], SUBS_OPTIONS,
+                          'illegal passthrough macro subs option')
+            else:
+                subslist = self.subslist
+            passtext = Lex.subs_1(passtext,subslist)
+            if passtext is None: passtext = ''
+            if self.prefix == '':
+                # Unescape ] characters in inline macros.
+                passtext = passtext.replace('\\]',']')
+            passthroughs.append(passtext)
+            # Tabs guarantee the placeholders are unambiguous.
+            result = (
+                text[mo.start():mo.start('passtext')] +
+                '\x07' + str(len(passthroughs)-1) + '\x07' +
+                text[mo.end('passtext'):mo.end()]
+            )
+            return result
+
+        return self.reo.sub(subs_func, text)
+
+
+class CalloutMap:
+    def __init__(self):
+        self.comap = {}         # key = list index, value = callouts list.
+        self.calloutindex = 0   # Current callout index number.
+        self.listnumber = 1     # Current callout list number.
+    def listclose(self):
+        # Called when callout list is closed.
+        self.listnumber += 1
+        self.calloutindex = 0
+        self.comap = {}
+    def add(self,listindex):
+        # Add next callout index to listindex map entry. Return the callout id.
+        self.calloutindex += 1
+        # Append the coindex to a list in the comap dictionary.
+        if not listindex in self.comap:
+            self.comap[listindex] = [self.calloutindex]
+        else:
+            self.comap[listindex].append(self.calloutindex)
+        return self.calloutid(self.listnumber, self.calloutindex)
+    @staticmethod
+    def calloutid(listnumber,calloutindex):
+        return 'CO%d-%d' % (listnumber,calloutindex)
+    def calloutids(self,listindex):
+        # Retieve list of callout indexes that refer to listindex.
+        if listindex in self.comap:
+            result = ''
+            for coindex in self.comap[listindex]:
+                result += ' ' + self.calloutid(self.listnumber,coindex)
+            return result.strip()
+        else:
+            message.warning('no callouts refer to list item '+str(listindex))
+            return ''
+    def validate(self,maxlistindex):
+        # Check that all list indexes referenced by callouts exist.
+        for listindex in self.comap.keys():
+            if listindex > maxlistindex:
+                message.warning('callout refers to non-existent list item '
+                        + str(listindex))
+
+#---------------------------------------------------------------------------
+# Input stream Reader and output stream writer classes.
+#---------------------------------------------------------------------------
+
+UTF8_BOM = '\xef\xbb\xbf'
+
+class Reader1:
+    """Line oriented AsciiDoc input file reader. Processes include and
+    conditional inclusion system macros. Tabs are expanded and lines are right
+    trimmed."""
+    # This class is not used directly, use Reader class instead.
+    READ_BUFFER_MIN = 10        # Read buffer low level.
+    def __init__(self):
+        self.f = None           # Input file object.
+        self.fname = None       # Input file name.
+        self.next = []          # Read ahead buffer containing
+                                # [filename,linenumber,linetext] lists.
+        self.cursor = None      # Last read() [filename,linenumber,linetext].
+        self.tabsize = 8        # Tab expansion number of spaces.
+        self.parent = None      # Included reader's parent reader.
+        self._lineno = 0        # The last line read from file object f.
+        self.current_depth = 0  # Current include depth.
+        self.max_depth = 5      # Initial maxiumum allowed include depth.
+        self.bom = None         # Byte order mark (BOM).
+        self.infile = None      # Saved document 'infile' attribute.
+        self.indir = None       # Saved document 'indir' attribute.
+    def open(self,fname):
+        self.fname = fname
+        message.verbose('reading: '+fname)
+        if fname == '<stdin>':
+            self.f = sys.stdin
+            self.infile = None
+            self.indir = None
+        else:
+            self.f = open(fname,'rb')
+            self.infile = fname
+            self.indir = os.path.dirname(fname)
+        document.attributes['infile'] = self.infile
+        document.attributes['indir'] = self.indir
+        self._lineno = 0            # The last line read from file object f.
+        self.next = []
+        # Prefill buffer by reading the first line and then pushing it back.
+        if Reader1.read(self):
+            if self.cursor[2].startswith(UTF8_BOM):
+                self.cursor[2] = self.cursor[2][len(UTF8_BOM):]
+                self.bom = UTF8_BOM
+            self.unread(self.cursor)
+            self.cursor = None
+    def closefile(self):
+        """Used by class methods to close nested include files."""
+        self.f.close()
+        self.next = []
+    def close(self):
+        self.closefile()
+        self.__init__()
+    def read(self, skip=False):
+        """Read next line. Return None if EOF. Expand tabs. Strip trailing
+        white space. Maintain self.next read ahead buffer. If skip=True then
+        conditional exclusion is active (ifdef and ifndef macros)."""
+        # Top up buffer.
+        if len(self.next) <= self.READ_BUFFER_MIN:
+            s = self.f.readline()
+            if s:
+                self._lineno = self._lineno + 1
+            while s:
+                if self.tabsize != 0:
+                    s = s.expandtabs(self.tabsize)
+                s = s.rstrip()
+                self.next.append([self.fname,self._lineno,s])
+                if len(self.next) > self.READ_BUFFER_MIN:
+                    break
+                s = self.f.readline()
+                if s:
+                    self._lineno = self._lineno + 1
+        # Return first (oldest) buffer entry.
+        if len(self.next) > 0:
+            self.cursor = self.next[0]
+            del self.next[0]
+            result = self.cursor[2]
+            # Check for include macro.
+            mo = macros.match('+',r'include[1]?',result)
+            if mo and not skip:
+                # Don't process include macro once the maximum depth is reached.
+                if self.current_depth >= self.max_depth:
+                    return result
+                # Perform attribute substitution on include macro file name.
+                fname = subs_attrs(mo.group('target'))
+                if not fname:
+                    return Reader1.read(self)   # Return next input line.
+                if self.fname != '<stdin>':
+                    fname = os.path.expandvars(os.path.expanduser(fname))
+                    fname = safe_filename(fname, os.path.dirname(self.fname))
+                    if not fname:
+                        return Reader1.read(self)   # Return next input line.
+                    if mo.group('name') == 'include1':
+                        if not config.dumping:
+                            # Store the include file in memory for later
+                            # retrieval by the {include1:} system attribute.
+                            config.include1[fname] = [
+                                s.rstrip() for s in open(fname)]
+                            return '{include1:%s}' % fname
+                        else:
+                            # This is a configuration dump, just pass the macro
+                            # call through.
+                            return result
+                # Parse include macro attributes.
+                attrs = {}
+                parse_attributes(mo.group('attrlist'),attrs)
+                # Clone self and set as parent (self assumes the role of child).
+                parent = Reader1()
+                assign(parent,self)
+                self.parent = parent
+                # Set attributes in child.
+                if 'tabsize' in attrs:
+                    self.tabsize = int(validate(attrs['tabsize'],
+                        'int($)>=0',
+                        'illegal include macro tabsize argument'))
+                else:
+                    self.tabsize = config.tabsize
+                if 'depth' in attrs:
+                    attrs['depth'] = int(validate(attrs['depth'],
+                        'int($)>=1',
+                        'illegal include macro depth argument'))
+                    self.max_depth = self.current_depth + attrs['depth']
+                # Process included file.
+                self.open(fname)
+                self.current_depth = self.current_depth + 1
+                result = Reader1.read(self)
+        else:
+            if not Reader1.eof(self):
+                result = Reader1.read(self)
+            else:
+                result = None
+        return result
+    def eof(self):
+        """Returns True if all lines have been read."""
+        if len(self.next) == 0:
+            # End of current file.
+            if self.parent:
+                self.closefile()
+                assign(self,self.parent)    # Restore parent reader.
+                document.attributes['infile'] = self.infile
+                document.attributes['indir'] = self.indir
+                return Reader1.eof(self)
+            else:
+                return True
+        else:
+            return False
+    def read_next(self):
+        """Like read() but does not advance file pointer."""
+        if Reader1.eof(self):
+            return None
+        else:
+            return self.next[0][2]
+    def unread(self,cursor):
+        """Push the line (filename,linenumber,linetext) tuple back into the read
+        buffer. Note that it's up to the caller to restore the previous
+        cursor."""
+        assert cursor
+        self.next.insert(0,cursor)
+
+class Reader(Reader1):
+    """ Wraps (well, sought of) Reader1 class and implements conditional text
+    inclusion."""
+    def __init__(self):
+        Reader1.__init__(self)
+        self.depth = 0          # if nesting depth.
+        self.skip = False       # true if we're skipping ifdef...endif.
+        self.skipname = ''      # Name of current endif macro target.
+        self.skipto = -1        # The depth at which skipping is reenabled.
+    def read_super(self):
+        result = Reader1.read(self,self.skip)
+        if result is None and self.skip:
+            raise EAsciiDoc,'missing endif::%s[]' % self.skipname
+        return result
+    def read(self):
+        result = self.read_super()
+        if result is None:
+            return None
+        while self.skip:
+            mo = macros.match('+',r'ifdef|ifndef|ifeval|endif',result)
+            if mo:
+                name = mo.group('name')
+                target = mo.group('target')
+                attrlist = mo.group('attrlist')
+                if name == 'endif':
+                    self.depth -= 1
+                    if self.depth < 0:
+                        raise EAsciiDoc,'mismatched macro: %s' % result
+                    if self.depth == self.skipto:
+                        self.skip = False
+                        if target and self.skipname != target:
+                            raise EAsciiDoc,'mismatched macro: %s' % result
+                else:
+                    if name in ('ifdef','ifndef'):
+                        if not target:
+                            raise EAsciiDoc,'missing macro target: %s' % result
+                        if not attrlist:
+                            self.depth += 1
+                    elif name == 'ifeval':
+                        if not attrlist:
+                            raise EAsciiDoc,'missing ifeval condition: %s' % result
+                        self.depth += 1
+            result = self.read_super()
+            if result is None:
+                return None
+        mo = macros.match('+',r'ifdef|ifndef|ifeval|endif',result)
+        if mo:
+            name = mo.group('name')
+            target = mo.group('target')
+            attrlist = mo.group('attrlist')
+            if name == 'endif':
+                self.depth = self.depth-1
+            else:
+                if not target and name in ('ifdef','ifndef'):
+                    raise EAsciiDoc,'missing macro target: %s' % result
+                defined = is_attr_defined(target, document.attributes)
+                if name == 'ifdef':
+                    if attrlist:
+                        if defined: return attrlist
+                    else:
+                        self.skip = not defined
+                elif name == 'ifndef':
+                    if attrlist:
+                        if not defined: return attrlist
+                    else:
+                        self.skip = defined
+                elif name == 'ifeval':
+                    if not attrlist:
+                        raise EAsciiDoc,'missing ifeval condition: %s' % result
+                    cond = False
+                    attrlist = subs_attrs(attrlist)
+                    if attrlist:
+                        try:
+                            cond = eval(attrlist)
+                        except Exception,e:
+                            raise EAsciiDoc,'error evaluating ifeval condition: %s: %s' % (result, str(e))
+                    self.skip = not cond
+                if not attrlist or name == 'ifeval':
+                    if self.skip:
+                        self.skipto = self.depth
+                        self.skipname = target
+                    self.depth = self.depth+1
+            result = self.read()
+        if result:
+            # Expand executable block macros.
+            mo = macros.match('+',r'eval|sys|sys2',result)
+            if mo:
+                action = mo.group('name')
+                cmd = mo.group('attrlist')
+                s = system(action, cmd, is_macro=True)
+                if s is not None:
+                    self.cursor[2] = s  # So we don't re-evaluate.
+                    result = s
+        if result:
+            # Unescape escaped system macros.
+            if macros.match('+',r'\\eval|\\sys|\\sys2|\\ifdef|\\ifndef|\\endif|\\include|\\include1',result):
+                result = result[1:]
+        return result
+    def eof(self):
+        return self.read_next() is None
+    def read_next(self):
+        save_cursor = self.cursor
+        result = self.read()
+        if result is not None:
+            self.unread(self.cursor)
+            self.cursor = save_cursor
+        return result
+    def read_lines(self,count=1):
+        """Return tuple containing count lines."""
+        result = []
+        i = 0
+        while i < count and not self.eof():
+            result.append(self.read())
+        return tuple(result)
+    def read_ahead(self,count=1):
+        """Same as read_lines() but does not advance the file pointer."""
+        result = []
+        putback = []
+        save_cursor = self.cursor
+        try:
+            i = 0
+            while i < count and not self.eof():
+                result.append(self.read())
+                putback.append(self.cursor)
+                i = i+1
+            while putback:
+                self.unread(putback.pop())
+        finally:
+            self.cursor = save_cursor
+        return tuple(result)
+    def skip_blank_lines(self):
+        reader.read_until(r'\s*\S+')
+    def read_until(self,terminators,same_file=False):
+        """Like read() but reads lines up to (but not including) the first line
+        that matches the terminator regular expression, regular expression
+        object or list of regular expression objects. If same_file is True then
+        the terminating pattern must occur in the file the was being read when
+        the routine was called."""
+        if same_file:
+            fname = self.cursor[0]
+        result = []
+        if not isinstance(terminators,list):
+            if isinstance(terminators,basestring):
+                terminators = [re.compile(terminators)]
+            else:
+                terminators = [terminators]
+        while not self.eof():
+            save_cursor = self.cursor
+            s = self.read()
+            if not same_file or fname == self.cursor[0]:
+                for reo in terminators:
+                    if reo.match(s):
+                        self.unread(self.cursor)
+                        self.cursor = save_cursor
+                        return tuple(result)
+            result.append(s)
+        return tuple(result)
+
+class Writer:
+    """Writes lines to output file."""
+    def __init__(self):
+        self.newline = '\r\n'            # End of line terminator.
+        self.f = None                    # Output file object.
+        self.fname = None                # Output file name.
+        self.lines_out = 0               # Number of lines written.
+        self.skip_blank_lines = False    # If True don't output blank lines.
+    def open(self,fname,bom=None):
+        '''
+        bom is optional byte order mark.
+        http://en.wikipedia.org/wiki/Byte-order_mark
+        '''
+        self.fname = fname
+        if fname == '<stdout>':
+            self.f = sys.stdout
+        else:
+            self.f = open(fname,'wb+')
+        message.verbose('writing: '+writer.fname,False)
+        if bom:
+            self.f.write(bom)
+        self.lines_out = 0
+    def close(self):
+        if self.fname != '<stdout>':
+            self.f.close()
+    def write_line(self, line=None):
+        if not (self.skip_blank_lines and (not line or not line.strip())):
+            self.f.write((line or '') + self.newline)
+            self.lines_out = self.lines_out + 1
+    def write(self,*args,**kwargs):
+        """Iterates arguments, writes tuple and list arguments one line per
+        element, else writes argument as single line. If no arguments writes
+        blank line. If argument is None nothing is written. self.newline is
+        appended to each line."""
+        if 'trace' in kwargs and len(args) > 0:
+            trace(kwargs['trace'],args[0])
+        if len(args) == 0:
+            self.write_line()
+            self.lines_out = self.lines_out + 1
+        else:
+            for arg in args:
+                if is_array(arg):
+                    for s in arg:
+                        self.write_line(s)
+                elif arg is not None:
+                    self.write_line(arg)
+    def write_tag(self,tag,content,subs=None,d=None,**kwargs):
+        """Write content enveloped by tag.
+        Substitutions specified in the 'subs' list are perform on the
+        'content'."""
+        if subs is None:
+            subs = config.subsnormal
+        stag,etag = subs_tag(tag,d)
+        content = Lex.subs(content,subs)
+        if 'trace' in kwargs:
+            trace(kwargs['trace'],[stag]+content+[etag])
+        if stag:
+            self.write(stag)
+        if content:
+            self.write(content)
+        if etag:
+            self.write(etag)
+
+#---------------------------------------------------------------------------
+# Configuration file processing.
+#---------------------------------------------------------------------------
+def _subs_specialwords(mo):
+    """Special word substitution function called by
+    Config.subs_specialwords()."""
+    word = mo.re.pattern                    # The special word.
+    template = config.specialwords[word]    # The corresponding markup template.
+    if not template in config.sections:
+        raise EAsciiDoc,'missing special word template [%s]' % template
+    if mo.group()[0] == '\\':
+        return mo.group()[1:]   # Return escaped word.
+    args = {}
+    args['words'] = mo.group()  # The full match string is argument 'words'.
+    args.update(mo.groupdict()) # Add other named match groups to the arguments.
+    # Delete groups that didn't participate in match.
+    for k,v in args.items():
+        if v is None: del args[k]
+    lines = subs_attrs(config.sections[template],args)
+    if len(lines) == 0:
+        result = ''
+    elif len(lines) == 1:
+        result = lines[0]
+    else:
+        result = writer.newline.join(lines)
+    return result
+
+class Config:
+    """Methods to process configuration files."""
+    # Non-template section name regexp's.
+    ENTRIES_SECTIONS= ('tags','miscellaneous','attributes','specialcharacters',
+            'specialwords','macros','replacements','quotes','titles',
+            r'paradef-.+',r'listdef-.+',r'blockdef-.+',r'tabledef-.+',
+            r'tabletags-.+',r'listtags-.+','replacements2',
+            r'old_tabledef-.+')
+    def __init__(self):
+        self.sections = OrderedDict()   # Keyed by section name containing
+                                        # lists of section lines.
+        # Command-line options.
+        self.verbose = False
+        self.header_footer = True       # -s, --no-header-footer option.
+        # [miscellaneous] section.
+        self.tabsize = 8
+        self.textwidth = 70             # DEPRECATED: Old tables only.
+        self.newline = '\r\n'
+        self.pagewidth = None
+        self.pageunits = None
+        self.outfilesuffix = ''
+        self.subsnormal = SUBS_NORMAL
+        self.subsverbatim = SUBS_VERBATIM
+
+        self.tags = {}          # Values contain (stag,etag) tuples.
+        self.specialchars = {}  # Values of special character substitutions.
+        self.specialwords = {}  # Name is special word pattern, value is macro.
+        self.replacements = OrderedDict()   # Key is find pattern, value is
+                                            #replace pattern.
+        self.replacements2 = OrderedDict()
+        self.specialsections = {} # Name is special section name pattern, value
+                                  # is corresponding section name.
+        self.quotes = OrderedDict()    # Values contain corresponding tag name.
+        self.fname = ''         # Most recently loaded configuration file name.
+        self.conf_attrs = {}    # Attributes entries from conf files.
+        self.cmd_attrs = {}     # Attributes from command-line -a options.
+        self.loaded = []        # Loaded conf files.
+        self.include1 = {}      # Holds include1::[] files for {include1:}.
+        self.dumping = False    # True if asciidoc -c option specified.
+
+    def init(self, cmd):
+        """
+        Check Python version and locate the executable and configuration files
+        directory.
+        cmd is the asciidoc command or asciidoc.py path.
+        """
+        if float(sys.version[:3]) < MIN_PYTHON_VERSION:
+            message.stderr('FAILED: Python 2.3 or better required')
+            sys.exit(1)
+        if not os.path.exists(cmd):
+            message.stderr('FAILED: Missing asciidoc command: %s' % cmd)
+            sys.exit(1)
+        global APP_FILE
+        APP_FILE = os.path.realpath(cmd)
+        global APP_DIR
+        APP_DIR = os.path.dirname(APP_FILE)
+        global USER_DIR
+        USER_DIR = userdir()
+        if USER_DIR is not None:
+            USER_DIR = os.path.join(USER_DIR,'.asciidoc')
+            if not os.path.isdir(USER_DIR):
+                USER_DIR = None
+
+    def load_file(self, fname, dir=None, include=[], exclude=[]):
+        """
+        Loads sections dictionary with sections from file fname.
+        Existing sections are overlaid.
+        The 'include' list contains the section names to be loaded.
+        The 'exclude' list contains section names not to be loaded.
+        Return False if no file was found in any of the locations.
+        """
+        if dir:
+            fname = os.path.join(dir, fname)
+        # Sliently skip missing configuration file.
+        if not os.path.isfile(fname):
+            return False
+        # Don't load conf files twice (local and application conf files are the
+        # same if the source file is in the application directory).
+        if os.path.realpath(fname) in self.loaded:
+            return True
+        rdr = Reader()  # Reader processes system macros.
+        message.linenos = False         # Disable document line numbers.
+        rdr.open(fname)
+        message.linenos = None
+        self.fname = fname
+        reo = re.compile(r'(?u)^\[(?P<section>[^\W\d][\w-]*)\]\s*$')
+        sections = OrderedDict()
+        section,contents = '',[]
+        while not rdr.eof():
+            s = rdr.read()
+            if s and s[0] == '#':       # Skip comment lines.
+                continue
+            if s[:2] == '\\#':          # Unescape lines starting with '#'.
+                s = s[1:]
+            s = s.rstrip()
+            found = reo.findall(s)
+            if found:
+                if section:             # Store previous section.
+                    if section in sections \
+                        and self.entries_section(section):
+                        if ''.join(contents):
+                            # Merge entries.
+                            sections[section] = sections[section] + contents
+                        else:
+                            del sections[section]
+                    else:
+                        sections[section] = contents
+                section = found[0].lower()
+                contents = []
+            else:
+                contents.append(s)
+        if section and contents:        # Store last section.
+            if section in sections \
+                and self.entries_section(section):
+                if ''.join(contents):
+                    # Merge entries.
+                    sections[section] = sections[section] + contents
+                else:
+                    del sections[section]
+            else:
+                sections[section] = contents
+        rdr.close()
+        if include:
+            for s in set(sections) - set(include):
+                del sections[s]
+        if exclude:
+            for s in set(sections) & set(exclude):
+                del sections[s]
+        attrs = {}
+        self.load_sections(sections,attrs)
+        if not include:
+            # If all sections are loaded mark this file as loaded.
+            self.loaded.append(os.path.realpath(fname))
+        document.update_attributes(attrs) # So they are available immediately.
+        return True
+
+    def load_sections(self,sections,attrs=None):
+        """
+        Loads sections dictionary. Each dictionary entry contains a
+        list of lines.
+        Updates 'attrs' with parsed [attributes] section entries.
+        """
+        # Delete trailing blank lines from sections.
+        for k in sections.keys():
+            for i in range(len(sections[k])-1,-1,-1):
+                if not sections[k][i]:
+                    del sections[k][i]
+                elif not self.entries_section(k):
+                    break
+        # Add/overwrite new sections.
+        self.sections.update(sections)
+        self.parse_tags()
+        # Internally [miscellaneous] section entries are just attributes.
+        d = {}
+        parse_entries(sections.get('miscellaneous',()), d, unquote=True,
+                allow_name_only=True)
+        parse_entries(sections.get('attributes',()), d, unquote=True,
+                allow_name_only=True)
+        update_attrs(self.conf_attrs,d)
+        if attrs is not None:
+            attrs.update(d)
+        d = {}
+        parse_entries(sections.get('titles',()),d)
+        Title.load(d)
+        parse_entries(sections.get('specialcharacters',()),self.specialchars,escape_delimiter=False)
+        parse_entries(sections.get('quotes',()),self.quotes)
+        self.parse_specialwords()
+        self.parse_replacements()
+        self.parse_replacements('replacements2')
+        self.parse_specialsections()
+        paragraphs.load(sections)
+        lists.load(sections)
+        blocks.load(sections)
+        tables_OLD.load(sections)
+        tables.load(sections)
+        macros.load(sections.get('macros',()))
+
+    def get_load_dirs(self):
+        """
+        Return list of well known paths with conf files.
+        """
+        result = []
+        if localapp():
+            # Load from folders in asciidoc executable directory.
+            result.append(APP_DIR)
+        else:
+            # Load from global configuration directory.
+            result.append(CONF_DIR)
+        # Load configuration files from ~/.asciidoc if it exists.
+        if USER_DIR is not None:
+            result.append(USER_DIR)
+        return result
+
+    def find_in_dirs(self, filename, dirs=None):
+        """
+        Find conf files from dirs list.
+        Return list of found file paths.
+        Return empty list if not found in any of the locations.
+        """
+        result = []
+        if dirs is None:
+            dirs = self.get_load_dirs()
+        for d in dirs:
+            f = os.path.join(d,filename)
+            if os.path.isfile(f):
+                result.append(f)
+        return result
+
+    def load_from_dirs(self, filename, dirs=None, include=[]):
+        """
+        Load conf file from dirs list.
+        If dirs not specified try all the well known locations.
+        Return False if no file was sucessfully loaded.
+        """
+        count = 0
+        for f in self.find_in_dirs(filename,dirs):
+            if self.load_file(f, include=include):
+                count += 1
+        return count != 0
+
+    def load_backend(self, dirs=None):
+        """
+        Load the backend configuration files from dirs list.
+        If dirs not specified try all the well known locations.
+        """
+        if dirs is None:
+            dirs = self.get_load_dirs()
+        for d in dirs:
+            conf = document.backend + '.conf'
+            self.load_file(conf,d)
+            conf = document.backend + '-' + document.doctype + '.conf'
+            self.load_file(conf,d)
+
+    def load_filters(self, dirs=None):
+        """
+        Load filter configuration files from 'filters' directory in dirs list.
+        If dirs not specified try all the well known locations.
+        """
+        if dirs is None:
+            dirs = self.get_load_dirs()
+        for d in dirs:
+            # Load filter .conf files.
+            filtersdir = os.path.join(d,'filters')
+            for dirpath,dirnames,filenames in os.walk(filtersdir):
+                for f in filenames:
+                    if re.match(r'^.+\.conf$',f):
+                        self.load_file(f,dirpath)
+
+    def load_miscellaneous(self,d):
+        """Set miscellaneous configuration entries from dictionary 'd'."""
+        def set_misc(name,rule='True',intval=False):
+            if name in d:
+                errmsg = 'illegal [miscellaneous] %s entry' % name
+                if intval:
+                    setattr(self, name, int(validate(d[name],rule,errmsg)))
+                else:
+                    setattr(self, name, validate(d[name],rule,errmsg))
+        set_misc('tabsize','int($)>0',intval=True)
+        set_misc('textwidth','int($)>0',intval=True) # DEPRECATED: Old tables only.
+        set_misc('pagewidth','"%f" % $')
+        if 'pagewidth' in d:
+            self.pagewidth = float(self.pagewidth)
+        set_misc('pageunits')
+        set_misc('outfilesuffix')
+        if 'newline' in d:
+            # Convert escape sequences to their character values.
+            self.newline = eval('"'+d['newline']+'"')
+        if 'subsnormal' in d:
+            self.subsnormal = parse_options(d['subsnormal'],SUBS_OPTIONS,
+                    'illegal [%s] %s: %s' %
+                    ('miscellaneous','subsnormal',d['subsnormal']))
+        if 'subsverbatim' in d:
+            self.subsverbatim = parse_options(d['subsverbatim'],SUBS_OPTIONS,
+                    'illegal [%s] %s: %s' %
+                    ('miscellaneous','subsverbatim',d['subsverbatim']))
+
+    def validate(self):
+        """Check the configuration for internal consistancy. Called after all
+        configuration files have been loaded."""
+        message.linenos = False     # Disable document line numbers.
+        # Heuristic to validate that at least one configuration file was loaded.
+        if not self.specialchars or not self.tags or not lists:
+            raise EAsciiDoc,'incomplete configuration files'
+        # Check special characters are only one character long.
+        for k in self.specialchars.keys():
+            if len(k) != 1:
+                raise EAsciiDoc,'[specialcharacters] ' \
+                                'must be a single character: %s' % k
+        # Check all special words have a corresponding inline macro body.
+        for macro in self.specialwords.values():
+            if not is_name(macro):
+                raise EAsciiDoc,'illegal special word name: %s' % macro
+            if not macro in self.sections:
+                message.warning('missing special word macro: [%s]' % macro)
+        # Check all text quotes have a corresponding tag.
+        for q in self.quotes.keys()[:]:
+            tag = self.quotes[q]
+            if not tag:
+                del self.quotes[q]  # Undefine quote.
+            else:
+                if tag[0] == '#':
+                    tag = tag[1:]
+                if not tag in self.tags:
+                    message.warning('[quotes] %s missing tag definition: %s' % (q,tag))
+        # Check all specialsections section names exist.
+        for k,v in self.specialsections.items():
+            if not v:
+                del self.specialsections[k]
+            elif not v in self.sections:
+                message.warning('missing specialsections section: [%s]' % v)
+        paragraphs.validate()
+        lists.validate()
+        blocks.validate()
+        tables_OLD.validate()
+        tables.validate()
+        macros.validate()
+        message.linenos = None
+
+    def entries_section(self,section_name):
+        """
+        Return True if conf file section contains entries, not a markup
+        template.
+        """
+        for name in self.ENTRIES_SECTIONS:
+            if re.match(name,section_name):
+                return True
+        return False
+
+    def dump(self):
+        """Dump configuration to stdout."""
+        # Header.
+        hdr = ''
+        hdr = hdr + '#' + writer.newline
+        hdr = hdr + '# Generated by AsciiDoc %s for %s %s.%s' % \
+            (VERSION,document.backend,document.doctype,writer.newline)
+        t = time.asctime(time.localtime(time.time()))
+        hdr = hdr + '# %s%s' % (t,writer.newline)
+        hdr = hdr + '#' + writer.newline
+        sys.stdout.write(hdr)
+        # Dump special sections.
+        # Dump only the configuration file and command-line attributes.
+        # [miscellanous] entries are dumped as part of the [attributes].
+        d = {}
+        d.update(self.conf_attrs)
+        d.update(self.cmd_attrs)
+        dump_section('attributes',d)
+        Title.dump()
+        dump_section('quotes',self.quotes)
+        dump_section('specialcharacters',self.specialchars)
+        d = {}
+        for k,v in self.specialwords.items():
+            if v in d:
+                d[v] = '%s "%s"' % (d[v],k)   # Append word list.
+            else:
+                d[v] = '"%s"' % k
+        dump_section('specialwords',d)
+        dump_section('replacements',self.replacements)
+        dump_section('replacements2',self.replacements2)
+        dump_section('specialsections',self.specialsections)
+        d = {}
+        for k,v in self.tags.items():
+            d[k] = '%s|%s' % v
+        dump_section('tags',d)
+        paragraphs.dump()
+        lists.dump()
+        blocks.dump()
+        tables_OLD.dump()
+        tables.dump()
+        macros.dump()
+        # Dump remaining sections.
+        for k in self.sections.keys():
+            if not self.entries_section(k):
+                sys.stdout.write('[%s]%s' % (k,writer.newline))
+                for line in self.sections[k]:
+                    sys.stdout.write('%s%s' % (line,writer.newline))
+                sys.stdout.write(writer.newline)
+
+    def subs_section(self,section,d):
+        """Section attribute substitution using attributes from
+        document.attributes and 'd'.  Lines containing undefinded
+        attributes are deleted."""
+        if section in self.sections:
+            return subs_attrs(self.sections[section],d)
+        else:
+            message.warning('missing section: [%s]' % section)
+            return ()
+
+    def parse_tags(self):
+        """Parse [tags] section entries into self.tags dictionary."""
+        d = {}
+        parse_entries(self.sections.get('tags',()),d)
+        for k,v in d.items():
+            if v is None:
+                if k in self.tags:
+                    del self.tags[k]
+            elif v == '':
+                self.tags[k] = (None,None)
+            else:
+                mo = re.match(r'(?P<stag>.*)\|(?P<etag>.*)',v)
+                if mo:
+                    self.tags[k] = (mo.group('stag'), mo.group('etag'))
+                else:
+                    raise EAsciiDoc,'[tag] %s value malformed' % k
+
+    def tag(self, name, d=None):
+        """Returns (starttag,endtag) tuple named name from configuration file
+        [tags] section. Raise error if not found. If a dictionary 'd' is
+        passed then merge with document attributes and perform attribute
+        substitution on tags."""
+        if not name in self.tags:
+            raise EAsciiDoc, 'missing tag: %s' % name
+        stag,etag = self.tags[name]
+        if d is not None:
+            # TODO: Should we warn if substitution drops a tag?
+            if stag:
+                stag = subs_attrs(stag,d)
+            if etag:
+                etag = subs_attrs(etag,d)
+        if stag is None: stag = ''
+        if etag is None: etag = ''
+        return (stag,etag)
+
+    def parse_specialsections(self):
+        """Parse specialsections section to self.specialsections dictionary."""
+        # TODO: This is virtually the same as parse_replacements() and should
+        # be factored to single routine.
+        d = {}
+        parse_entries(self.sections.get('specialsections',()),d,unquote=True)
+        for pat,sectname in d.items():
+            pat = strip_quotes(pat)
+            if not is_re(pat):
+                raise EAsciiDoc,'[specialsections] entry ' \
+                                'is not a valid regular expression: %s' % pat
+            if sectname is None:
+                if pat in self.specialsections:
+                    del self.specialsections[pat]
+            else:
+                self.specialsections[pat] = sectname
+
+    def parse_replacements(self,sect='replacements'):
+        """Parse replacements section into self.replacements dictionary."""
+        d = OrderedDict()
+        parse_entries(self.sections.get(sect,()), d, unquote=True)
+        for pat,rep in d.items():
+            if not self.set_replacement(pat, rep, getattr(self,sect)):
+                raise EAsciiDoc,'[%s] entry in %s is not a valid' \
+                    ' regular expression: %s' % (sect,self.fname,pat)
+
+    @staticmethod
+    def set_replacement(pat, rep, replacements):
+        """Add pattern and replacement to replacements dictionary."""
+        pat = strip_quotes(pat)
+        if not is_re(pat):
+            return False
+        if rep is None:
+            if pat in replacements:
+                del replacements[pat]
+        else:
+            replacements[pat] = strip_quotes(rep)
+        return True
+
+    def subs_replacements(self,s,sect='replacements'):
+        """Substitute patterns from self.replacements in 's'."""
+        result = s
+        for pat,rep in getattr(self,sect).items():
+            result = re.sub(pat, rep, result)
+        return result
+
+    def parse_specialwords(self):
+        """Parse special words section into self.specialwords dictionary."""
+        reo = re.compile(r'(?:\s|^)(".+?"|[^"\s]+)(?=\s|$)')
+        for line in self.sections.get('specialwords',()):
+            e = parse_entry(line)
+            if not e:
+                raise EAsciiDoc,'[specialwords] entry in %s is malformed: %s' \
+                    % (self.fname,line)
+            name,wordlist = e
+            if not is_name(name):
+                raise EAsciiDoc,'[specialwords] name in %s is illegal: %s' \
+                    % (self.fname,name)
+            if wordlist is None:
+                # Undefine all words associated with 'name'.
+                for k,v in self.specialwords.items():
+                    if v == name:
+                        del self.specialwords[k]
+            else:
+                words = reo.findall(wordlist)
+                for word in words:
+                    word = strip_quotes(word)
+                    if not is_re(word):
+                        raise EAsciiDoc,'[specialwords] entry in %s ' \
+                            'is not a valid regular expression: %s' \
+                            % (self.fname,word)
+                    self.specialwords[word] = name
+
+    def subs_specialchars(self,s):
+        """Perform special character substitution on string 's'."""
+        """It may seem like a good idea to escape special characters with a '\'
+        character, the reason we don't is because the escape character itself
+        then has to be escaped and this makes including code listings
+        problematic. Use the predefined {amp},{lt},{gt} attributes instead."""
+        result = ''
+        for ch in s:
+            result = result + self.specialchars.get(ch,ch)
+        return result
+
+    def subs_specialchars_reverse(self,s):
+        """Perform reverse special character substitution on string 's'."""
+        result = s
+        for k,v in self.specialchars.items():
+            result = result.replace(v, k)
+        return result
+
+    def subs_specialwords(self,s):
+        """Search for word patterns from self.specialwords in 's' and
+        substitute using corresponding macro."""
+        result = s
+        for word in self.specialwords.keys():
+            result = re.sub(word, _subs_specialwords, result)
+        return result
+
+    def expand_templates(self,entries):
+        """Expand any template::[] macros in a list of section entries."""
+        result = []
+        for line in entries:
+            mo = macros.match('+',r'template',line)
+            if mo:
+                s = mo.group('attrlist')
+                if s in self.sections:
+                    result += self.expand_templates(self.sections[s])
+                else:
+                    message.warning('missing section: [%s]' % s)
+                    result.append(line)
+            else:
+                result.append(line)
+        return result
+
+    def expand_all_templates(self):
+        for k,v in self.sections.items():
+            self.sections[k] = self.expand_templates(v)
+
+    def section2tags(self, section, d={}, skipstart=False, skipend=False):
+        """Perform attribute substitution on 'section' using document
+        attributes plus 'd' attributes. Return tuple (stag,etag) containing
+        pre and post | placeholder tags. 'skipstart' and 'skipend' are
+        used to suppress substitution."""
+        assert section is not None
+        if section in self.sections:
+            body = self.sections[section]
+        else:
+            message.warning('missing section: [%s]' % section)
+            body = ()
+        # Split macro body into start and end tag lists.
+        stag = []
+        etag = []
+        in_stag = True
+        for s in body:
+            if in_stag:
+                mo = re.match(r'(?P<stag>.*)\|(?P<etag>.*)',s)
+                if mo:
+                    if mo.group('stag'):
+                        stag.append(mo.group('stag'))
+                    if mo.group('etag'):
+                        etag.append(mo.group('etag'))
+                    in_stag = False
+                else:
+                    stag.append(s)
+            else:
+                etag.append(s)
+        # Do attribute substitution last so {brkbar} can be used to escape |.
+        # But don't do attribute substitution on title -- we've already done it.
+        title = d.get('title')
+        if title:
+            d['title'] = chr(0)  # Replace with unused character.
+        if not skipstart:
+            stag = subs_attrs(stag, d)
+        if not skipend:
+            etag = subs_attrs(etag, d)
+        # Put the {title} back.
+        if title:
+            stag = map(lambda x: x.replace(chr(0), title), stag)
+            etag = map(lambda x: x.replace(chr(0), title), etag)
+            d['title'] = title
+        return (stag,etag)
+
+
+#---------------------------------------------------------------------------
+# Deprecated old table classes follow.
+# Naming convention is an _OLD name suffix.
+# These will be removed from future versions of AsciiDoc
+
+def join_lines_OLD(lines):
+    """Return a list in which lines terminated with the backslash line
+    continuation character are joined."""
+    result = []
+    s = ''
+    continuation = False
+    for line in lines:
+        if line and line[-1] == '\\':
+            s = s + line[:-1]
+            continuation = True
+            continue
+        if continuation:
+            result.append(s+line)
+            s = ''
+            continuation = False
+        else:
+            result.append(line)
+    if continuation:
+        result.append(s)
+    return result
+
+class Column_OLD:
+    """Table column."""
+    def __init__(self):
+        self.colalign = None    # 'left','right','center'
+        self.rulerwidth = None
+        self.colwidth = None    # Output width in page units.
+
+class Table_OLD(AbstractBlock):
+    COL_STOP = r"(`|'|\.)"  # RE.
+    ALIGNMENTS = {'`':'left', "'":'right', '.':'center'}
+    FORMATS = ('fixed','csv','dsv')
+    def __init__(self):
+        AbstractBlock.__init__(self)
+        self.CONF_ENTRIES += ('template','fillchar','format','colspec',
+                              'headrow','footrow','bodyrow','headdata',
+                              'footdata', 'bodydata')
+        # Configuration parameters.
+        self.fillchar=None
+        self.format=None    # 'fixed','csv','dsv'
+        self.colspec=None
+        self.headrow=None
+        self.footrow=None
+        self.bodyrow=None
+        self.headdata=None
+        self.footdata=None
+        self.bodydata=None
+        # Calculated parameters.
+        self.underline=None     # RE matching current table underline.
+        self.isnumeric=False    # True if numeric ruler.
+        self.tablewidth=None    # Optional table width scale factor.
+        self.columns=[]         # List of Columns.
+        # Other.
+        self.check_msg=''       # Message set by previous self.validate() call.
+    def load(self,name,entries):
+        AbstractBlock.load(self,name,entries)
+        """Update table definition from section entries in 'entries'."""
+        for k,v in entries.items():
+            if k == 'fillchar':
+                if v and len(v) == 1:
+                    self.fillchar = v
+                else:
+                    raise EAsciiDoc,'malformed table fillchar: %s' % v
+            elif k == 'format':
+                if v in Table_OLD.FORMATS:
+                    self.format = v
+                else:
+                    raise EAsciiDoc,'illegal table format: %s' % v
+            elif k == 'colspec':
+                self.colspec = v
+            elif k == 'headrow':
+                self.headrow = v
+            elif k == 'footrow':
+                self.footrow = v
+            elif k == 'bodyrow':
+                self.bodyrow = v
+            elif k == 'headdata':
+                self.headdata = v
+            elif k == 'footdata':
+                self.footdata = v
+            elif k == 'bodydata':
+                self.bodydata = v
+    def dump(self):
+        AbstractBlock.dump(self)
+        write = lambda s: sys.stdout.write('%s%s' % (s,writer.newline))
+        write('fillchar='+self.fillchar)
+        write('format='+self.format)
+        if self.colspec:
+            write('colspec='+self.colspec)
+        if self.headrow:
+            write('headrow='+self.headrow)
+        if self.footrow:
+            write('footrow='+self.footrow)
+        write('bodyrow='+self.bodyrow)
+        if self.headdata:
+            write('headdata='+self.headdata)
+        if self.footdata:
+            write('footdata='+self.footdata)
+        write('bodydata='+self.bodydata)
+        write('')
+    def validate(self):
+        AbstractBlock.validate(self)
+        """Check table definition and set self.check_msg if invalid else set
+        self.check_msg to blank string."""
+        # Check global table parameters.
+        if config.textwidth is None:
+            self.check_msg = 'missing [miscellaneous] textwidth entry'
+        elif config.pagewidth is None:
+            self.check_msg = 'missing [miscellaneous] pagewidth entry'
+        elif config.pageunits is None:
+            self.check_msg = 'missing [miscellaneous] pageunits entry'
+        elif self.headrow is None:
+            self.check_msg = 'missing headrow entry'
+        elif self.footrow is None:
+            self.check_msg = 'missing footrow entry'
+        elif self.bodyrow is None:
+            self.check_msg = 'missing bodyrow entry'
+        elif self.headdata is None:
+            self.check_msg = 'missing headdata entry'
+        elif self.footdata is None:
+            self.check_msg = 'missing footdata entry'
+        elif self.bodydata is None:
+            self.check_msg = 'missing bodydata entry'
+        else:
+            # No errors.
+            self.check_msg = ''
+    def isnext(self):
+        return AbstractBlock.isnext(self)
+    def parse_ruler(self,ruler):
+        """Parse ruler calculating underline and ruler column widths."""
+        fc = re.escape(self.fillchar)
+        # Strip and save optional tablewidth from end of ruler.
+        mo = re.match(r'^(.*'+fc+r'+)([\d\.]+)$',ruler)
+        if mo:
+            ruler = mo.group(1)
+            self.tablewidth = float(mo.group(2))
+            self.attributes['tablewidth'] = str(float(self.tablewidth))
+        else:
+            self.tablewidth = None
+            self.attributes['tablewidth'] = '100.0'
+        # Guess whether column widths are specified numerically or not.
+        if ruler[1] != self.fillchar:
+            # If the first column does not start with a fillchar then numeric.
+            self.isnumeric = True
+        elif ruler[1:] == self.fillchar*len(ruler[1:]):
+            # The case of one column followed by fillchars is numeric.
+            self.isnumeric = True
+        else:
+            self.isnumeric = False
+        # Underlines must be 3 or more fillchars.
+        self.underline = r'^' + fc + r'{3,}$'
+        splits = re.split(self.COL_STOP,ruler)[1:]
+        # Build self.columns.
+        for i in range(0,len(splits),2):
+            c = Column_OLD()
+            c.colalign = self.ALIGNMENTS[splits[i]]
+            s = splits[i+1]
+            if self.isnumeric:
+                # Strip trailing fillchars.
+                s = re.sub(fc+r'+$','',s)
+                if s == '':
+                    c.rulerwidth = None
+                else:
+                    c.rulerwidth = int(validate(s,'int($)>0',
+                        'malformed ruler: bad width'))
+            else:   # Calculate column width from inter-fillchar intervals.
+                if not re.match(r'^'+fc+r'+$',s):
+                    raise EAsciiDoc,'malformed ruler: illegal fillchars'
+                c.rulerwidth = len(s)+1
+            self.columns.append(c)
+        # Fill in unspecified ruler widths.
+        if self.isnumeric:
+            if self.columns[0].rulerwidth is None:
+                prevwidth = 1
+            for c in self.columns:
+                if c.rulerwidth is None:
+                    c.rulerwidth = prevwidth
+                prevwidth = c.rulerwidth
+    def build_colspecs(self):
+        """Generate colwidths and colspecs. This can only be done after the
+        table arguments have been parsed since we use the table format."""
+        self.attributes['cols'] = len(self.columns)
+        # Calculate total ruler width.
+        totalwidth = 0
+        for c in self.columns:
+            totalwidth = totalwidth + c.rulerwidth
+        if totalwidth <= 0:
+            raise EAsciiDoc,'zero width table'
+        # Calculate marked up colwidths from rulerwidths.
+        for c in self.columns:
+            # Convert ruler width to output page width.
+            width = float(c.rulerwidth)
+            if self.format == 'fixed':
+                if self.tablewidth is None:
+                    # Size proportional to ruler width.
+                    colfraction = width/config.textwidth
+                else:
+                    # Size proportional to page width.
+                    colfraction = width/totalwidth
+            else:
+                    # Size proportional to page width.
+                colfraction = width/totalwidth
+            c.colwidth = colfraction * config.pagewidth # To page units.
+            if self.tablewidth is not None:
+                c.colwidth = c.colwidth * self.tablewidth   # Scale factor.
+                if self.tablewidth > 1:
+                    c.colwidth = c.colwidth/100 # tablewidth is in percent.
+        # Build colspecs.
+        if self.colspec:
+            cols = []
+            i = 0
+            for c in self.columns:
+                i += 1
+                self.attributes['colalign'] = c.colalign
+                self.attributes['colwidth'] = str(int(c.colwidth))
+                self.attributes['colnumber'] = str(i + 1)
+                s = subs_attrs(self.colspec,self.attributes)
+                if not s:
+                    message.warning('colspec dropped: contains undefined attribute')
+                else:
+                    cols.append(s)
+            self.attributes['colspecs'] = writer.newline.join(cols)
+    def split_rows(self,rows):
+        """Return a two item tuple containing a list of lines up to but not
+        including the next underline (continued lines are joined ) and the
+        tuple of all lines after the underline."""
+        reo = re.compile(self.underline)
+        i = 0
+        while not reo.match(rows[i]):
+            i = i+1
+        if i == 0:
+            raise EAsciiDoc,'missing table rows'
+        if i >= len(rows):
+            raise EAsciiDoc,'closing [%s] underline expected' % self.name
+        return (join_lines_OLD(rows[:i]), rows[i+1:])
+    def parse_rows(self, rows, rtag, dtag):
+        """Parse rows list using the row and data tags. Returns a substituted
+        list of output lines."""
+        result = []
+        # Source rows are parsed as single block, rather than line by line, to
+        # allow the CSV reader to handle multi-line rows.
+        if self.format == 'fixed':
+            rows = self.parse_fixed(rows)
+        elif self.format == 'csv':
+            rows = self.parse_csv(rows)
+        elif self.format == 'dsv':
+            rows = self.parse_dsv(rows)
+        else:
+            assert True,'illegal table format'
+        # Substitute and indent all data in all rows.
+        stag,etag = subs_tag(rtag,self.attributes)
+        for row in rows:
+            result.append('  '+stag)
+            for data in self.subs_row(row,dtag):
+                result.append('    '+data)
+            result.append('  '+etag)
+        return result
+    def subs_row(self, data, dtag):
+        """Substitute the list of source row data elements using the data tag.
+        Returns a substituted list of output table data items."""
+        result = []
+        if len(data) < len(self.columns):
+            message.warning('fewer row data items then table columns')
+        if len(data) > len(self.columns):
+            message.warning('more row data items than table columns')
+        for i in range(len(self.columns)):
+            if i > len(data) - 1:
+                d = ''  # Fill missing column data with blanks.
+            else:
+                d = data[i]
+            c = self.columns[i]
+            self.attributes['colalign'] = c.colalign
+            self.attributes['colwidth'] = str(int(c.colwidth))
+            self.attributes['colnumber'] = str(i + 1)
+            stag,etag = subs_tag(dtag,self.attributes)
+            # Insert AsciiDoc line break (' +') where row data has newlines
+            # ('\n').  This is really only useful when the table format is csv
+            # and the output markup is HTML. It's also a bit dubious in that it
+            # assumes the user has not modified the shipped line break pattern.
+            subs = self.get_subs()[0]
+            if 'replacements' in subs:
+                # Insert line breaks in cell data.
+                d = re.sub(r'(?m)\n',r' +\n',d)
+                d = d.split('\n')    # So writer.newline is written.
+            else:
+                d = [d]
+            result = result + [stag] + Lex.subs(d,subs) + [etag]
+        return result
+    def parse_fixed(self,rows):
+        """Parse the list of source table rows. Each row item in the returned
+        list contains a list of cell data elements."""
+        result = []
+        for row in rows:
+            data = []
+            start = 0
+            # build an encoded representation
+            row = char_decode(row)
+            for c in self.columns:
+                end = start + c.rulerwidth
+                if c is self.columns[-1]:
+                    # Text in last column can continue forever.
+                    # Use the encoded string to slice, but convert back
+                    # to plain string before further processing
+                    data.append(char_encode(row[start:]).strip())
+                else:
+                    data.append(char_encode(row[start:end]).strip())
+                start = end
+            result.append(data)
+        return result
+    def parse_csv(self,rows):
+        """Parse the list of source table rows. Each row item in the returned
+        list contains a list of cell data elements."""
+        import StringIO
+        import csv
+        result = []
+        rdr = csv.reader(StringIO.StringIO('\r\n'.join(rows)),
+            skipinitialspace=True)
+        try:
+            for row in rdr:
+                result.append(row)
+        except Exception:
+            raise EAsciiDoc,'csv parse error: %s' % row
+        return result
+    def parse_dsv(self,rows):
+        """Parse the list of source table rows. Each row item in the returned
+        list contains a list of cell data elements."""
+        separator = self.attributes.get('separator',':')
+        separator = eval('"'+separator+'"')
+        if len(separator) != 1:
+            raise EAsciiDoc,'malformed dsv separator: %s' % separator
+        # TODO If separator is preceeded by an odd number of backslashes then
+        # it is escaped and should not delimit.
+        result = []
+        for row in rows:
+            # Skip blank lines
+            if row == '': continue
+            # Unescape escaped characters.
+            row = eval('"'+row.replace('"','\\"')+'"')
+            data = row.split(separator)
+            data = [s.strip() for s in data]
+            result.append(data)
+        return result
+    def translate(self):
+        message.deprecated('old tables syntax')
+        AbstractBlock.translate(self)
+        # Reset instance specific properties.
+        self.underline = None
+        self.columns = []
+        attrs = {}
+        BlockTitle.consume(attrs)
+        # Add relevant globals to table substitutions.
+        attrs['pagewidth'] = str(config.pagewidth)
+        attrs['pageunits'] = config.pageunits
+        # Mix in document attribute list.
+        AttributeList.consume(attrs)
+        # Validate overridable attributes.
+        for k,v in attrs.items():
+            if k == 'format':
+                if v not in self.FORMATS:
+                    raise EAsciiDoc, 'illegal [%s] %s: %s' % (self.name,k,v)
+                self.format = v
+            elif k == 'tablewidth':
+                try:
+                    self.tablewidth = float(attrs['tablewidth'])
+                except Exception:
+                    raise EAsciiDoc, 'illegal [%s] %s: %s' % (self.name,k,v)
+        self.merge_attributes(attrs)
+        # Parse table ruler.
+        ruler = reader.read()
+        assert re.match(self.delimiter,ruler)
+        self.parse_ruler(ruler)
+        # Read the entire table.
+        table = []
+        while True:
+            line = reader.read_next()
+            # Table terminated by underline followed by a blank line or EOF.
+            if len(table) > 0 and re.match(self.underline,table[-1]):
+                if line in ('',None):
+                    break;
+            if line is None:
+                raise EAsciiDoc,'closing [%s] underline expected' % self.name
+            table.append(reader.read())
+        # EXPERIMENTAL: The number of lines in the table, requested by Benjamin Klum.
+        self.attributes['rows'] = str(len(table))
+        if self.check_msg:  # Skip if table definition was marked invalid.
+            message.warning('skipping %s table: %s' % (self.name,self.check_msg))
+            return
+        # Generate colwidths and colspecs.
+        self.build_colspecs()
+        # Generate headrows, footrows, bodyrows.
+        # Headrow, footrow and bodyrow data replaces same named attributes in
+        # the table markup template. In order to ensure this data does not get
+        # a second attribute substitution (which would interfere with any
+        # already substituted inline passthroughs) unique placeholders are used
+        # (the tab character does not appear elsewhere since it is expanded on
+        # input) which are replaced after template attribute substitution.
+        headrows = footrows = []
+        bodyrows,table = self.split_rows(table)
+        if table:
+            headrows = bodyrows
+            bodyrows,table = self.split_rows(table)
+            if table:
+                footrows,table = self.split_rows(table)
+        if headrows:
+            headrows = self.parse_rows(headrows, self.headrow, self.headdata)
+            headrows = writer.newline.join(headrows)
+            self.attributes['headrows'] = '\x07headrows\x07'
+        if footrows:
+            footrows = self.parse_rows(footrows, self.footrow, self.footdata)
+            footrows = writer.newline.join(footrows)
+            self.attributes['footrows'] = '\x07footrows\x07'
+        bodyrows = self.parse_rows(bodyrows, self.bodyrow, self.bodydata)
+        bodyrows = writer.newline.join(bodyrows)
+        self.attributes['bodyrows'] = '\x07bodyrows\x07'
+        table = subs_attrs(config.sections[self.template],self.attributes)
+        table = writer.newline.join(table)
+        # Before we finish replace the table head, foot and body place holders
+        # with the real data.
+        if headrows:
+            table = table.replace('\x07headrows\x07', headrows, 1)
+        if footrows:
+            table = table.replace('\x07footrows\x07', footrows, 1)
+        table = table.replace('\x07bodyrows\x07', bodyrows, 1)
+        writer.write(table,trace='table')
+
+class Tables_OLD(AbstractBlocks):
+    """List of tables."""
+    BLOCK_TYPE = Table_OLD
+    PREFIX = 'old_tabledef-'
+    def __init__(self):
+        AbstractBlocks.__init__(self)
+    def load(self,sections):
+        AbstractBlocks.load(self,sections)
+    def validate(self):
+        # Does not call AbstractBlocks.validate().
+        # Check we have a default table definition,
+        for i in range(len(self.blocks)):
+            if self.blocks[i].name == 'old_tabledef-default':
+                default = self.blocks[i]
+                break
+        else:
+            raise EAsciiDoc,'missing section: [OLD_tabledef-default]'
+        # Set default table defaults.
+        if default.format is None: default.subs = 'fixed'
+        # Propagate defaults to unspecified table parameters.
+        for b in self.blocks:
+            if b is not default:
+                if b.fillchar is None: b.fillchar = default.fillchar
+                if b.format is None: b.format = default.format
+                if b.template is None: b.template = default.template
+                if b.colspec is None: b.colspec = default.colspec
+                if b.headrow is None: b.headrow = default.headrow
+                if b.footrow is None: b.footrow = default.footrow
+                if b.bodyrow is None: b.bodyrow = default.bodyrow
+                if b.headdata is None: b.headdata = default.headdata
+                if b.footdata is None: b.footdata = default.footdata
+                if b.bodydata is None: b.bodydata = default.bodydata
+        # Check all tables have valid fill character.
+        for b in self.blocks:
+            if not b.fillchar or len(b.fillchar) != 1:
+                raise EAsciiDoc,'[%s] missing or illegal fillchar' % b.name
+        # Build combined tables delimiter patterns and assign defaults.
+        delimiters = []
+        for b in self.blocks:
+            # Ruler is:
+            #   (ColStop,(ColWidth,FillChar+)?)+, FillChar+, TableWidth?
+            b.delimiter = r'^(' + Table_OLD.COL_STOP \
+                + r'(\d*|' + re.escape(b.fillchar) + r'*)' \
+                + r')+' \
+                + re.escape(b.fillchar) + r'+' \
+                + '([\d\.]*)$'
+            delimiters.append(b.delimiter)
+            if not b.headrow:
+                b.headrow = b.bodyrow
+            if not b.footrow:
+                b.footrow = b.bodyrow
+            if not b.headdata:
+                b.headdata = b.bodydata
+            if not b.footdata:
+                b.footdata = b.bodydata
+        self.delimiters = re_join(delimiters)
+        # Check table definitions are valid.
+        for b in self.blocks:
+            b.validate()
+            if config.verbose:
+                if b.check_msg:
+                    message.warning('[%s] table definition: %s' % (b.name,b.check_msg))
+
+# End of deprecated old table classes.
+#---------------------------------------------------------------------------
+
+#---------------------------------------------------------------------------
+# Filter commands.
+#---------------------------------------------------------------------------
+import shutil, zipfile
+
+def die(msg):
+    message.stderr(msg)
+    sys.exit(1)
+
+def unzip(zip_file, destdir):
+    """
+    Unzip Zip file to destination directory.
+    Throws exception if error occurs.
+    """
+    zipo = zipfile.ZipFile(zip_file, 'r')
+    try:
+        for zi in zipo.infolist():
+            outfile = zi.filename
+            if not outfile.endswith('/'):
+                d, outfile = os.path.split(outfile)
+                directory = os.path.normpath(os.path.join(destdir, d))
+                if not os.path.isdir(directory):
+                    os.makedirs(directory)
+                outfile = os.path.join(directory, outfile)
+                perms = (zi.external_attr >> 16) & 0777
+                message.verbose('extracting: %s' % outfile)
+                fh = os.open(outfile, os.O_CREAT | os.O_WRONLY, perms)
+                try:
+                    os.write(fh, zipo.read(zi.filename))
+                finally:
+                    os.close(fh)
+    finally:
+        zipo.close()
+
+class Filter:
+    """
+    --filter option commands.
+    """
+
+    @staticmethod
+    def get_filters_dir():
+        """
+        Return path of .asciidoc/filters in user's home direcory or None if
+        user home not defined.
+        """
+        result = userdir()
+        if result:
+            result = os.path.join(result,'.asciidoc','filters')
+        return result
+
+    @staticmethod
+    def install(args):
+        """
+        Install filter Zip file.
+        args[0] is filter zip file path.
+        args[1] is optional destination filters directory.
+        """
+        if len(args) not in (1,2):
+            die('invalid number of arguments: --filter install %s'
+                    % ' '.join(args))
+        zip_file = args[0]
+        if not os.path.isfile(zip_file):
+            die('file not found: %s' % zip_file)
+        reo = re.match(r'^\w+',os.path.split(zip_file)[1])
+        if not reo:
+            die('filter file name does not start with legal filter name: %s'
+                    % zip_file)
+        filter_name = reo.group()
+        if len(args) == 2:
+            filters_dir = args[1]
+            if not os.path.isdir(filters_dir):
+                die('directory not found: %s' % filters_dir)
+        else:
+            filters_dir = Filter.get_filters_dir()
+            if not filters_dir:
+                die('user home directory is not defined')
+        filter_dir = os.path.join(filters_dir, filter_name)
+        if os.path.exists(filter_dir):
+            die('filter is already installed: %s' % filter_dir)
+        try:
+            os.makedirs(filter_dir)
+        except Exception,e:
+            die('failed to create filter directory: %s' % str(e))
+        try:
+            unzip(zip_file, filter_dir)
+        except Exception,e:
+            die('failed to extract filter: %s' % str(e))
+
+    @staticmethod
+    def remove(args):
+        """
+        Delete filter from .asciidoc/filters/ in user's home directory.
+        args[0] is filter name.
+        args[1] is optional filters directory.
+        """
+        if len(args) not in (1,2):
+            die('invalid number of arguments: --filter remove %s'
+                    % ' '.join(args))
+        filter_name = args[0]
+        if not re.match(r'^\w+$',filter_name):
+            die('illegal filter name: %s' % filter_name)
+        if len(args) == 2:
+            d = args[1]
+            if not os.path.isdir(d):
+                die('directory not found: %s' % d)
+        else:
+            d = Filter.get_filters_dir()
+            if not d:
+                die('user directory is not defined')
+        filter_dir = os.path.join(d, filter_name)
+        if not os.path.isdir(filter_dir):
+            die('cannot find filter: %s' % filter_dir)
+        try:
+            message.verbose('removing: %s' % filter_dir)
+            shutil.rmtree(filter_dir)
+        except Exception,e:
+            die('failed to delete filter: %s' % str(e))
+
+    @staticmethod
+    def list():
+        """
+        List all filter directories (global and local).
+        """
+        for d in [os.path.join(d,'filters') for d in config.get_load_dirs()]:
+            if os.path.isdir(d):
+                for f in os.walk(d).next()[1]:
+                    message.stdout(os.path.join(d,f))
+
+
+#---------------------------------------------------------------------------
+# Application code.
+#---------------------------------------------------------------------------
+# Constants
+# ---------
+APP_FILE = None             # This file's full path.
+APP_DIR = None              # This file's directory.
+USER_DIR = None             # ~/.asciidoc
+# Global configuration files directory (set by Makefile build target).
+CONF_DIR = '/etc/asciidoc'
+HELP_FILE = 'help.conf'     # Default (English) help file.
+
+# Globals
+# -------
+document = Document()       # The document being processed.
+config = Config()           # Configuration file reader.
+reader = Reader()           # Input stream line reader.
+writer = Writer()           # Output stream line writer.
+message = Message()         # Message functions.
+paragraphs = Paragraphs()   # Paragraph definitions.
+lists = Lists()             # List definitions.
+blocks = DelimitedBlocks()  # DelimitedBlock definitions.
+tables_OLD = Tables_OLD()   # Table_OLD definitions.
+tables = Tables()           # Table definitions.
+macros = Macros()           # Macro definitions.
+calloutmap = CalloutMap()   # Coordinates callouts and callout list.
+trace = Trace()             # Implements trace attribute processing.
+
+### Used by asciidocapi.py ###
+# List of message strings written to stderr.
+messages = message.messages
+
+
+def asciidoc(backend, doctype, confiles, infile, outfile, options):
+    """Convert AsciiDoc document to DocBook document of type doctype
+    The AsciiDoc document is read from file object src the translated
+    DocBook file written to file object dst."""
+    def load_conffiles(include=[], exclude=[]):
+        # Load conf files specified on the command-line and by the conf-files attribute.
+        files = document.attributes.get('conf-files','')
+        files = [f.strip() for f in files.split('|') if f.strip()]
+        files += confiles
+        if files:
+            for f in files:
+                if os.path.isfile(f):
+                    config.load_file(f, include=include, exclude=exclude)
+                else:
+                    raise EAsciiDoc,'configuration file %s missing' % f
+
+    try:
+        if doctype not in (None,'article','manpage','book'):
+            raise EAsciiDoc,'illegal document type'
+        # Set processing options.
+        for o in options:
+            if o == '-c': config.dumping = True
+            if o == '-s': config.header_footer = False
+            if o == '-v': config.verbose = True
+        document.update_attributes()
+        if '-e' not in options:
+            # Load asciidoc.conf files in two passes: the first for attributes
+            # the second for everything. This is so that locally set attributes
+            # available are in the global asciidoc.conf
+            if not config.load_from_dirs('asciidoc.conf',include=['attributes']):
+                raise EAsciiDoc,'configuration file asciidoc.conf missing'
+            load_conffiles(include=['attributes'])
+            config.load_from_dirs('asciidoc.conf')
+            if infile != '<stdin>':
+                indir = os.path.dirname(infile)
+                config.load_file('asciidoc.conf', indir,
+                                include=['attributes','titles','specialchars'])
+        else:
+            load_conffiles(include=['attributes','titles','specialchars'])
+        document.update_attributes()
+        # Check the infile exists.
+        if infile != '<stdin>':
+            if not os.path.isfile(infile):
+                raise EAsciiDoc,'input file %s missing' % infile
+        document.infile = infile
+        AttributeList.initialize()
+        # Open input file and parse document header.
+        reader.tabsize = config.tabsize
+        reader.open(infile)
+        has_header = document.parse_header(doctype,backend)
+        # doctype is now finalized.
+        document.attributes['doctype-'+document.doctype] = ''
+        # Load backend configuration files.
+        if '-e' not in options:
+            f = document.backend + '.conf'
+            if not config.find_in_dirs(f):
+                message.warning('missing backend conf file: %s' % f, linenos=False)
+            config.load_backend()
+        # backend is now known.
+        document.attributes['backend-'+document.backend] = ''
+        document.attributes[document.backend+'-'+document.doctype] = ''
+        doc_conffiles = []
+        if '-e' not in options:
+            # Load filters and language file.
+            config.load_filters()
+            document.load_lang()
+            if infile != '<stdin>':
+                # Load local conf files (files in the source file directory).
+                config.load_file('asciidoc.conf', indir)
+                config.load_backend([indir])
+                config.load_filters([indir])
+                # Load document specific configuration files.
+                f = os.path.splitext(infile)[0]
+                doc_conffiles = [
+                        f for f in (f+'.conf', f+'-'+document.backend+'.conf')
+                        if os.path.isfile(f) ]
+                for f in doc_conffiles:
+                    config.load_file(f)
+        load_conffiles()
+        # Build asciidoc-args attribute.
+        args = ''
+        # Add custom conf file arguments.
+        for f in doc_conffiles + confiles:
+            args += ' --conf-file "%s"' % f
+        # Add command-line and header attributes.
+        attrs = {}
+        attrs.update(AttributeEntry.attributes)
+        attrs.update(config.cmd_attrs)
+        if 'title' in attrs:    # Don't pass the header title.
+            del attrs['title']
+        for k,v in attrs.items():
+            if v:
+                args += ' --attribute "%s=%s"' % (k,v)
+            else:
+                args += ' --attribute "%s"' % k
+        document.attributes['asciidoc-args'] = args
+        # Build outfile name.
+        if outfile is None:
+            outfile = os.path.splitext(infile)[0] + '.' + document.backend
+            if config.outfilesuffix:
+                # Change file extension.
+                outfile = os.path.splitext(outfile)[0] + config.outfilesuffix
+        document.outfile = outfile
+        # Document header attributes override conf file attributes.
+        document.attributes.update(AttributeEntry.attributes)
+        document.update_attributes()
+        # Configuration is fully loaded so can expand templates.
+        config.expand_all_templates()
+        # Check configuration for consistency.
+        config.validate()
+        paragraphs.initialize()
+        lists.initialize()
+        if config.dumping:
+            config.dump()
+        else:
+            writer.newline = config.newline
+            try:
+                writer.open(outfile, reader.bom)
+                try:
+                    document.translate(has_header) # Generate the output.
+                finally:
+                    writer.close()
+            finally:
+                reader.closefile()
+    except KeyboardInterrupt:
+        raise
+    except Exception,e:
+        # Cleanup.
+        if outfile and outfile != '<stdout>' and os.path.isfile(outfile):
+            os.unlink(outfile)
+        # Build and print error description.
+        msg = 'FAILED: '
+        if reader.cursor:
+            msg = message.format('', msg)
+        if isinstance(e, EAsciiDoc):
+            message.stderr('%s%s' % (msg,str(e)))
+        else:
+            if __name__ == '__main__':
+                message.stderr(msg+'unexpected error:')
+                message.stderr('-'*60)
+                traceback.print_exc(file=sys.stderr)
+                message.stderr('-'*60)
+            else:
+                message.stderr('%sunexpected error: %s' % (msg,str(e)))
+        sys.exit(1)
+
+def usage(msg=''):
+    if msg:
+        message.stderr(msg)
+    show_help('default', sys.stderr)
+
+def show_help(topic, f=None):
+    """Print help topic to file object f."""
+    if f is None:
+        f = sys.stdout
+    # Select help file.
+    lang = config.cmd_attrs.get('lang')
+    if lang and lang != 'en':
+        help_file = 'help-' + lang + '.conf'
+    else:
+        help_file = HELP_FILE
+    # Print [topic] section from help file.
+    config.load_from_dirs(help_file)
+    if len(config.sections) == 0:
+        # Default to English if specified language help files not found.
+        help_file = HELP_FILE
+        config.load_from_dirs(help_file)
+    if len(config.sections) == 0:
+        message.stderr('no help topics found')
+        sys.exit(1)
+    n = 0
+    for k in config.sections:
+        if re.match(re.escape(topic), k):
+            n += 1
+            lines = config.sections[k]
+    if n == 0:
+        if topic != 'topics':
+            message.stderr('help topic not found: [%s] in %s' % (topic, help_file))
+        message.stderr('available help topics: %s' % ', '.join(config.sections.keys()))
+        sys.exit(1)
+    elif n > 1:
+        message.stderr('ambiguous help topic: %s' % topic)
+    else:
+        for line in lines:
+            print >>f, line
+
+### Used by asciidocapi.py ###
+def execute(cmd,opts,args):
+    """
+    Execute asciidoc with command-line options and arguments.
+    cmd is asciidoc command or asciidoc.py path.
+    opts and args conform to values returned by getopt.getopt().
+    Raises SystemExit if an error occurs.
+
+    Doctests:
+
+    1. Check execution:
+
+       >>> import StringIO
+       >>> infile = StringIO.StringIO('Hello *{author}*')
+       >>> outfile = StringIO.StringIO()
+       >>> opts = []
+       >>> opts.append(('--backend','html4'))
+       >>> opts.append(('--no-header-footer',None))
+       >>> opts.append(('--attribute','author=Joe Bloggs'))
+       >>> opts.append(('--out-file',outfile))
+       >>> execute(__file__, opts, [infile])
+       >>> print outfile.getvalue()
+       <p>Hello <strong>Joe Bloggs</strong></p>
+
+       >>>
+
+    """
+    config.init(cmd)
+    if len(args) > 1:
+        usage('To many arguments')
+        sys.exit(1)
+    backend = None
+    doctype = None
+    confiles = []
+    outfile = None
+    options = []
+    help_option = False
+    for o,v in opts:
+        if o in ('--help','-h'):
+            help_option = True
+        #DEPRECATED: --unsafe option.
+        if o == '--unsafe':
+            document.safe = False
+        if o == '--safe':
+            document.safe = True
+        if o == '--version':
+            print('asciidoc %s' % VERSION)
+            sys.exit(0)
+        if o in ('-b','--backend'):
+            backend = v
+#            config.cmd_attrs['backend'] = v
+        if o in ('-c','--dump-conf'):
+            options.append('-c')
+        if o in ('-d','--doctype'):
+            doctype = v
+#            config.cmd_attrs['doctype'] = v
+        if o in ('-e','--no-conf'):
+            options.append('-e')
+        if o in ('-f','--conf-file'):
+            confiles.append(v)
+        if o in ('-n','--section-numbers'):
+            o = '-a'
+            v = 'numbered'
+        if o in ('-a','--attribute'):
+            e = parse_entry(v, allow_name_only=True)
+            if not e:
+                usage('Illegal -a option: %s' % v)
+                sys.exit(1)
+            k,v = e
+            # A @ suffix denotes don't override existing document attributes.
+            if v and v[-1] == '@':
+                document.attributes[k] = v[:-1]
+            else:
+                config.cmd_attrs[k] = v
+        if o in ('-o','--out-file'):
+            outfile = v
+        if o in ('-s','--no-header-footer'):
+            options.append('-s')
+        if o in ('-v','--verbose'):
+            options.append('-v')
+    if help_option:
+        if len(args) == 0:
+            show_help('default')
+        else:
+            show_help(args[-1])
+        sys.exit(0)
+    if len(args) == 0 and len(opts) == 0:
+        usage()
+        sys.exit(0)
+    if len(args) == 0:
+        usage('No source file specified')
+        sys.exit(1)
+#    if not backend:
+#        usage('No --backend option specified')
+#        sys.exit(1)
+    stdin,stdout = sys.stdin,sys.stdout
+    try:
+        infile = args[0]
+        if infile == '-':
+            infile = '<stdin>'
+        elif isinstance(infile, str):
+            infile = os.path.abspath(infile)
+        else:   # Input file is file object from API call.
+            sys.stdin = infile
+            infile = '<stdin>'
+        if outfile == '-':
+            outfile = '<stdout>'
+        elif isinstance(outfile, str):
+            outfile = os.path.abspath(outfile)
+        elif outfile is None:
+            if infile == '<stdin>':
+                outfile = '<stdout>'
+        else:   # Output file is file object from API call.
+            sys.stdout = outfile
+            outfile = '<stdout>'
+        # Do the work.
+        asciidoc(backend, doctype, confiles, infile, outfile, options)
+        if document.has_errors:
+            sys.exit(1)
+    finally:
+        sys.stdin,sys.stdout = stdin,stdout
+
+if __name__ == '__main__':
+    # Process command line options.
+    import getopt
+    try:
+        #DEPRECATED: --unsafe option.
+        opts,args = getopt.getopt(sys.argv[1:],
+            'a:b:cd:ef:hno:svw:',
+            ['attribute=','backend=','conf-file=','doctype=','dump-conf',
+            'help','no-conf','no-header-footer','out-file=',
+            'section-numbers','verbose','version','safe','unsafe',
+            'doctest','filter'])
+    except getopt.GetoptError:
+        message.stderr('illegal command options')
+        sys.exit(1)
+    if '--doctest' in [opt[0] for opt in opts]:
+        # Run module doctests.
+        import doctest
+        options = doctest.NORMALIZE_WHITESPACE + doctest.ELLIPSIS
+        failures,tries = doctest.testmod(optionflags=options)
+        if failures == 0:
+            message.stderr('All doctests passed')
+            sys.exit(0)
+        else:
+            sys.exit(1)
+    if '--filter' in [opt[0] for opt in opts]:
+        config.init(sys.argv[0])
+        config.verbose = bool(set(['-v','--verbose']) & set([opt[0] for opt in opts]))
+        if not args:
+            die('missing --filter command')
+        elif args[0] == 'install':
+            Filter.install(args[1:])
+        elif args[0] == 'remove':
+            Filter.remove(args[1:])
+        elif args[0] == 'list':
+            Filter.list()
+        else:
+            die('illegal --filter command: %s' % args[0])
+        sys.exit(0)
+    try:
+        execute(sys.argv[0],opts,args)
+    except KeyboardInterrupt:
+        sys.exit(1)
diff --git a/doc/www/create-relnotes.sh b/doc/www/create-relnotes.sh
new file mode 100755 (executable)
index 0000000..9e731e8
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# 
+# This script requires asciidoc http://www.methods.co.nz/asciidoc/
+
+# (echo -e "Netatalk NEWS\n-------------\n\n" ; cat NEWS) | ./asciidoc.py -f netatalk-news.conf -b css -o NEWS.html - && chmod g+w NEWS.html
+./asciidoc.py -f netatalk-relnotes.conf -b html5 -o ReleaseNotes.html ReleaseNotes && chmod g+w ReleaseNotes.html
diff --git a/doc/www/html5.conf b/doc/www/html5.conf
new file mode 100644 (file)
index 0000000..cedc3fd
--- /dev/null
@@ -0,0 +1,686 @@
+#
+# html5.conf
+#
+# Asciidoc configuration file.
+# html5 backend.
+#
+
+[miscellaneous]
+outfilesuffix=.html
+
+[attributes]
+basebackend=html
+basebackend-html=
+basebackend-html5=
+
+[replacements2]
+# Line break.
+(?m)^(.*)\s\+$=\1<br>
+
+[replacements]
+ifdef::asciidoc7compatible[]
+# Superscripts.
+\^(.+?)\^=<sup>\1</sup>
+# Subscripts.
+~(.+?)~=<sub>\1</sub>
+endif::asciidoc7compatible[]
+
+[ruler-blockmacro]
+<hr>
+
+[pagebreak-blockmacro]
+<div style="page-break-after:always"></div>
+
+[blockdef-pass]
+asciimath-style=template="asciimathblock",subs=[]
+latexmath-style=template="latexmathblock",subs=[]
+
+[macros]
+(?u)^(?P<name>audio|video)::(?P<target>\S*?)(\[(?P<attrlist>.*?)\])$=#
+# math macros.
+# Special characters are escaped in HTML math markup.
+(?su)[\\]?(?P<name>asciimath|latexmath):(?P<subslist>\S*?)\[(?P<passtext>.*?)(?<!\\)\]=[specialcharacters]
+(?u)^(?P<name>asciimath|latexmath)::(?P<subslist>\S*?)(\[(?P<passtext>.*?)\])$=#[specialcharacters]
+
+[asciimath-inlinemacro]
+`{passtext}`
+
+[asciimath-blockmacro]
+<div class="mathblock{role? {role}}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+`{passtext}`
+</div></div>
+
+[asciimathblock]
+<div class="mathblock{role? {role}}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+`|`
+</div></div>
+
+[latexmath-inlinemacro]
+{passtext}
+
+[latexmath-blockmacro]
+<div class="mathblock{role? {role}}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+{passtext}
+</div></div>
+
+[latexmathblock]
+<div class="mathblock{role? {role}}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+|
+</div></div>
+
+[image-inlinemacro]
+<span class="image{role? {role}}">
+<a class="image" href="{link}">
+{data-uri%}<img src="{imagesdir=}{imagesdir?/}{target}" alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}{title? title="{title}"}>
+{data-uri#}<img alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}{title? title="{title}"} src="data:image/{eval:os.path.splitext('{target}')[1][1:]};base64,
+{data-uri#}{sys3:python -uc "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join("{indir={outdir}}","{imagesdir=}","{target}")}"}">
+{link#}</a>
+</span>
+
+[image-blockmacro]
+<div class="imageblock{style? {style}}{role? {role}}"{id? id="{id}"}{align? style="text-align:{align};"}{float? style="float:{float};"}>
+<div class="content">
+<a class="image" href="{link}">
+{data-uri%}<img src="{imagesdir=}{imagesdir?/}{target}" alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"}>
+{data-uri#}<img alt="{alt={target}}"{width? width="{width}"}{height? height="{height}"} src="data:image/{eval:os.path.splitext('{target}')[1][1:]};base64,
+{data-uri#}{sys:python -uc "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join("{indir={outdir}}","{imagesdir=}","{target}")}"}">
+{link#}</a>
+</div>
+<div class="title">{caption={figure-caption} {counter:figure-number}. }{title}</div>
+</div>
+
+[audio-blockmacro]
+<div class="audioblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{caption=}{title}</div>
+<div class="content">
+<audio src="{imagesdir=}{imagesdir?/}{target}"{autoplay-option? autoplay}{nocontrols-option! controls}{loop-option? loop}>
+Your browser does not support the audio tag.
+</audio>
+</div></div>
+
+[video-blockmacro]
+<div class="videoblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{caption=}{title}</div>
+<div class="content">
+<video src="{imagesdir=}{imagesdir?/}{target}"{width? width="{width}"}{height? height="{height}"}{poster? poster="{poster}"}{autoplay-option? autoplay}{nocontrols-option! controls}{loop-option? loop}>
+Your browser does not support the video tag.
+</video>
+</div></div>
+
+[unfloat-blockmacro]
+<div style="clear:both;"></div>
+
+[indexterm-inlinemacro]
+# Index term.
+{empty}
+
+[indexterm2-inlinemacro]
+# Index term.
+# Single entry index term that is visible in the primary text flow.
+{1}
+
+[footnote-inlinemacro]
+# footnote:[<text>].
+<span class="footnote"><br>[{0}]<br></span>
+
+[footnoteref-inlinemacro]
+# footnoteref:[<id>], create reference to footnote.
+{2%}<span class="footnoteref"><br><a href="#_footnote_{1}">[{1}]</a><br></span>
+# footnoteref:[<id>,<text>], create footnote with ID.
+{2#}<span class="footnote" id="_footnote_{1}"><br>[{2}]<br></span>
+
+[callout-inlinemacro]
+ifndef::icons[]
+<b>&lt;{index}&gt;</b>
+endif::icons[]
+ifdef::icons[]
+ifndef::data-uri[]
+<img src="{icon={iconsdir}/callouts/{index}.png}" alt="{index}">
+endif::data-uri[]
+ifdef::data-uri[]
+<img alt="{index}" src="data:image/png;base64,
+{sys:python -uc "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join("{indir={outdir}}","{icon={iconsdir}/callouts/{index}.png}")}"}">
+endif::data-uri[]
+endif::icons[]
+
+# Comment line macros.
+[comment-inlinemacro]
+{showcomments#}<br><span class="comment">{passtext}</span><br>
+
+[comment-blockmacro]
+{showcomments#}<p><span class="comment">{passtext}</span></p>
+
+[literal-inlinemacro]
+# Inline literal.
+<span class="monospaced">{passtext}</span>
+
+# List tags.
+[listtags-bulleted]
+list=<div class="ulist{style? {style}}{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ul>|</ul></div>
+item=<li>|</li>
+text=<p>|</p>
+
+[listtags-numbered]
+# The start attribute is not valid XHTML 1.1 but all browsers support it.
+list=<div class="olist{style? {style}}{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ol class="{style}"{start? start="{start}"}>|</ol></div>
+item=<li>|</li>
+text=<p>|</p>
+
+[listtags-labeled]
+list=<div class="dlist{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<dl>|</dl></div>
+entry=
+label=
+term=<dt class="hdlist1{strong-option? strong}">|</dt>
+item=<dd>|</dd>
+text=<p>|</p>
+
+[listtags-horizontal]
+list=<div class="hdlist{compact-option? compact}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<table>{labelwidth?<col width="{labelwidth}%">}{itemwidth?<col width="{itemwidth}%">}|</table></div>
+label=<td class="hdlist1{strong-option? strong}">|</td>
+term=|<br>
+entry=<tr>|</tr>
+item=<td class="hdlist2">|</td>
+text=<p style="margin-top: 0;">|</p>
+
+[listtags-qanda]
+list=<div class="qlist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ol>|</ol></div>
+entry=<li>|</li>
+label=
+term=<p><em>|</em></p>
+item=
+text=<p>|</p>
+
+[listtags-callout]
+ifndef::icons[]
+list=<div class="colist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ol>|</ol></div>
+item=<li>|</li>
+text=<p>|</p>
+endif::icons[]
+ifdef::icons[]
+list=<div class="colist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<table>|</table></div>
+ifndef::data-uri[]
+item=<tr><td><img src="{iconsdir}/callouts/{listindex}.png" alt="{listindex}"></td><td>|</td></tr>
+endif::data-uri[]
+ifdef::data-uri[]
+item=<tr><td><img alt="{listindex}" src="data:image/png;base64, {sys:python -uc "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join("{indir={outdir}}","{icon={iconsdir}/callouts/{listindex}.png}")}"}"></td><td>|</td></tr>
+endif::data-uri[]
+text=|
+endif::icons[]
+
+[listtags-glossary]
+list=<div class="dlist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<dl>|</dl></div>
+label=
+entry=
+term=<dt>|</dt>
+item=<dd>|</dd>
+text=<p>|</p>
+
+[listtags-bibliography]
+list=<div class="ulist{style? {style}}{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<ul>|</ul></div>
+item=<li>|</li>
+text=<p>|</p>
+
+[tags]
+# Quoted text.
+emphasis=<em>{1?<span class="{1}">}|{1?</span>}</em>
+strong=<strong>{1?<span class="{1}">}|{1?</span>}</strong>
+monospaced=<span class="monospaced{1? {1}}">|</span>
+singlequoted={lsquo}{1?<span class="{1}">}|{1?</span>}{rsquo}
+doublequoted={ldquo}{1?<span class="{1}">}|{1?</span>}{rdquo}
+unquoted={1?<span class="{1}">}|{1?</span>}
+superscript=<sup>{1?<span class="{1}">}|{1?</span>}</sup>
+subscript=<sub>{1?<span class="{1}">}|{1?</span>}</sub>
+
+ifdef::deprecated-quotes[]
+# Override with deprecated quote attributes.
+emphasis={role?<span class="{role}">}<em{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</em>{role?</span>}
+strong={role?<span class="{role}">}<strong{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</strong>{role?</span>}
+monospaced=<span class="monospaced{role? {role}}"{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</span>
+singlequoted={role?<span class="{role}">}{1,2,3?<span style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?">}{amp}#8216;|{amp}#8217;{1,2,3?</span>}{role?</span>}
+doublequoted={role?<span class="{role}">}{1,2,3?<span style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?">}{amp}#8220;|{amp}#8221;{1,2,3?</span>}{role?</span>}
+unquoted={role?<span class="{role}">}{1,2,3?<span style="{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}">}|{1,2,3?</span>}{role?</span>}
+superscript={role?<span class="{role}">}<sup{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</sup>{role?</span>}
+subscript={role?<span class="{role}">}<sub{1,2,3? style="}{1?color:{1};}{2?background-color:{2};}{3?font-size:{3}em;}{1,2,3?"}>|</sub>{role?</span>}
+endif::deprecated-quotes[]
+
+# Inline macros
+[http-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[https-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[ftp-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[file-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[irc-inlinemacro]
+<a href="{name}:{target}">{0={name}:{target}}</a>
+[mailto-inlinemacro]
+<a href="mailto:{target}">{0={target}}</a>
+[link-inlinemacro]
+<a href="{target}">{0={target}}</a>
+[callto-inlinemacro]
+<a href="{name}:{target}">{0={target}}</a>
+# anchor:id[text]
+[anchor-inlinemacro]
+<a id="{target}"></a>
+# [[id,text]]
+[anchor2-inlinemacro]
+<a id="{1}"></a>
+# [[[id]]]
+[anchor3-inlinemacro]
+<a id="{1}"></a>[{1}]
+# xref:id[text]
+[xref-inlinemacro]
+<a href="#{target}">{0=[{target}]}</a>
+# <<id,text>>
+[xref2-inlinemacro]
+<a href="#{1}">{2=[{1}]}</a>
+
+# Special word substitution.
+[emphasizedwords]
+<em>{words}</em>
+[monospacedwords]
+<span class="monospaced">{words}</span>
+[strongwords]
+<strong>{words}</strong>
+
+# Paragraph substitution.
+[paragraph]
+<div class="paragraph{role? {role}}"{id? id="{id}"}>{title?<div class="title">{title}</div>}<p>
+|
+</p></div>
+
+[admonitionparagraph]
+template::[admonitionblock]
+
+# Delimited blocks.
+[listingblock]
+<div class="listingblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{caption=}{title}</div>
+<div class="content monospaced">
+<pre>
+|
+</pre>
+</div></div>
+
+[literalblock]
+<div class="literalblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<div class="content monospaced">
+<pre>
+|
+</pre>
+</div></div>
+
+[sidebarblock]
+<div class="sidebarblock{role? {role}}"{id? id="{id}"}>
+<div class="content">
+<div class="title">{title}</div>
+|
+</div></div>
+
+[openblock]
+<div class="openblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<div class="content">
+|
+</div></div>
+
+[partintroblock]
+template::[openblock]
+
+[abstractblock]
+template::[quoteblock]
+
+[quoteblock]
+<div class="quoteblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<div class="content">
+|
+</div>
+<div class="attribution">
+<em>{citetitle}</em>{attribution?<br>}
+&#8212; {attribution}
+</div></div>
+
+[verseblock]
+<div class="verseblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{title}</div>
+<pre class="content">
+|
+</pre>
+<div class="attribution">
+<em>{citetitle}</em>{attribution?<br>}
+&#8212; {attribution}
+</div></div>
+
+[exampleblock]
+<div class="exampleblock{role? {role}}"{id? id="{id}"}>
+<div class="title">{caption={example-caption} {counter:example-number}. }{title}</div>
+<div class="content">
+|
+</div></div>
+
+[admonitionblock]
+<div class="admonitionblock{role? {role}}"{id? id="{id}"}>
+<table><tr>
+<td class="icon">
+{data-uri%}{icons#}<img src="{icon={iconsdir}/{name}.png}" alt="{caption}">
+{data-uri#}{icons#}<img alt="{caption}" src="data:image/png;base64,
+{data-uri#}{icons#}{sys:python -uc "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join("{indir={outdir}}","{icon={iconsdir}/{name}.png}")}"}">
+{icons%}<div class="title">{caption}</div>
+</td>
+<td class="content">
+<div class="title">{title}</div>
+|
+</td>
+</tr></table>
+</div>
+
+# Tables.
+[tabletags-default]
+colspec=<col{autowidth-option! style="width:{colpcwidth}%;"}>
+bodyrow=<tr>|</tr>
+headdata=<th class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }>|</th>
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }>|</td>
+paragraph=<p class="tableblock">|</p>
+
+[tabletags-header]
+paragraph=<p class="tableblock header">|</p>
+
+[tabletags-emphasis]
+paragraph=<p class="tableblock"><em>|</em></p>
+
+[tabletags-strong]
+paragraph=<p class="tableblock"><strong>|</strong></p>
+
+[tabletags-monospaced]
+paragraph=<p class="tableblock monospaced">|</p>
+
+[tabletags-verse]
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }><div class="verse">|</div></td>
+paragraph=
+
+[tabletags-literal]
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }><div class="literal monospaced"><pre>|</pre></div></td>
+paragraph=
+
+[tabletags-asciidoc]
+bodydata=<td class="tableblock halign-{halign=left} valign-{valign=top}" {colspan@1::colspan="{colspan}" }{rowspan@1::rowspan="{rowspan}" }><div>|</div></td>
+paragraph=
+
+[table]
+<table class="tableblock frame-{frame=all} grid-{grid=all}{role? {role}}"{id? id="{id}"}
+style="
+margin-left:{align@left:0}{align@center|right:auto}; margin-right:{align@left|center:auto}{align@right:0};
+float:{float};
+{autowidth-option%}width:{tablepcwidth}%;
+{autowidth-option#}{width#style=width:{tablepcwidth}%;}
+">
+<caption class="title">{caption={table-caption} {counter:table-number}. }{title}</caption>
+{colspecs}
+{headrows#}<thead>
+{headrows}
+{headrows#}</thead>
+{footrows#}<tfoot>
+{footrows}
+{footrows#}</tfoot>
+<tbody>
+{bodyrows}
+</tbody>
+</table>
+
+#--------------------------------------------------------------------
+# Deprecated old table definitions.
+#
+
+[miscellaneous]
+# Screen width in pixels.
+pagewidth=800
+pageunits=px
+
+[old_tabledef-default]
+template=old_table
+colspec=<col style="width:{colwidth}{pageunits};" />
+bodyrow=<tr>|</tr>
+headdata=<th class="tableblock halign-{colalign=left}">|</th>
+footdata=<td class="tableblock halign-{colalign=left}">|</td>
+bodydata=<td class="tableblock halign-{colalign=left}">|</td>
+
+[old_table]
+<table class="tableblock frame-{frame=all} grid-{grid=all}"{id? id="{id}"}>
+<caption class="title">{caption={table-caption}}{title}</caption>
+{colspecs}
+{headrows#}<thead>
+{headrows}
+{headrows#}</thead>
+{footrows#}<tfoot>
+{footrows}
+{footrows#}</tfoot>
+<tbody style="vertical-align:top;">
+{bodyrows}
+</tbody>
+</table>
+
+# End of deprecated old table definitions.
+#--------------------------------------------------------------------
+
+[floatingtitle]
+<h{level@0:1}{level@1:2}{level@2:3}{level@3:4}{level@4:5}{id? id="{id}"} class="float">{title}</h{level@0:1}{level@1:2}{level@2:3}{level@3:4}{level@4:5}>
+
+[preamble]
+# Untitled elements between header and first section title.
+<div id="preamble">
+<div class="sectionbody">
+|
+</div>
+</div>
+
+# Document sections.
+[sect0]
+<h1{id? id="{id}"}>{title}</h1>
+|
+
+[sect1]
+<div class="sect1{style? {style}}{role? {role}}">
+<h2{id? id="{id}"}>{numbered?{sectnum} }{title}</h2>
+<div class="sectionbody">
+|
+</div>
+</div>
+
+[sect2]
+<div class="sect2{style? {style}}{role? {role}}">
+<h3{id? id="{id}"}>{numbered?{sectnum} }{title}</h3>
+|
+</div>
+
+[sect3]
+<div class="sect3{style? {style}}{role? {role}}">
+<h4{id? id="{id}"}>{numbered?{sectnum} }{title}</h4>
+|
+</div>
+
+[sect4]
+<div class="sect4{style? {style}}{role? {role}}">
+<h5{id? id="{id}"}>{title}</h5>
+|
+</div>
+
+[appendix]
+<div class="sect1{style? {style}}{role? {role}}">
+<h2{id? id="{id}"}>{numbered?{sectnum} }{appendix-caption} {counter:appendix-number:A}: {title}</h2>
+<div class="sectionbody">
+|
+</div>
+</div>
+
+[toc]
+<div id="toc">
+  <div id="toctitle">{toc-title}</div>
+  <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+
+[header]
+<!DOCTYPE html>
+<html lang="{lang=en}">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={encoding}">
+<meta name="generator" content="AsciiDoc {asciidoc-version}">
+<meta name="description" content="{description}">
+<meta name="keywords" content="{keywords}">
+<title>{title}</title>
+{title%}<title>{doctitle=}</title>
+ifdef::linkcss[]
+<link rel="stylesheet" href="{stylesdir=.}/{theme=asciidoc}.css" type="text/css">
+{doctype-manpage}<link rel="stylesheet" href="{stylesdir=.}/{theme=asciidoc}-manpage.css" type="text/css">
+ifdef::pygments[<link rel="stylesheet" href="{stylesdir=.}/pygments.css" type="text/css">]
+ifdef::toc2[<link rel="stylesheet" href="{stylesdir=.}/toc2.css" type="text/css" />]
+<link rel="stylesheet" href="{stylesdir=.}/{stylesheet}" type="text/css">
+endif::linkcss[]
+ifndef::linkcss[]
+<style type="text/css">
+include1::{stylesdir=./stylesheets}/{theme=asciidoc}.css[]
+ifdef::doctype-manpage[]
+include1::{stylesdir=./stylesheets}/{theme=asciidoc}-manpage.css[]
+endif::doctype-manpage[]
+ifdef::pygments[]
+include1::{stylesdir=./stylesheets}/pygments.css[]
+endif::pygments[]
+ifdef::toc2[]
+include1::{stylesdir=./stylesheets}/toc2.css[]
+endif::toc2[]
+include1::{stylesheet}[]
+</style>
+endif::linkcss[]
+ifndef::disable-javascript[]
+ifdef::linkcss[]
+<script type="text/javascript" src="{scriptsdir=.}/asciidoc.js"></script>
+<script type="text/javascript">
+#TODO: Escape not necessary in HTML5?
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+asciidoc.install({toc,toc2?{toclevels}});
+/*]]>*/
+</script>
+endif::linkcss[]
+ifndef::linkcss[]
+<script type="text/javascript">
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+include1::{scriptsdir=./javascripts}/asciidoc.js[]
+asciidoc.install({toc,toc2?{toclevels}});
+/*]]>*/
+</script>
+endif::linkcss[]
+endif::disable-javascript[]
+ifdef::asciimath[]
+ifdef::linkcss[]
+<script type="text/javascript" src="{scriptsdir=.}/ASCIIMathML.js"></script>
+endif::linkcss[]
+ifndef::linkcss[]
+<script type="text/javascript">
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+include1::{scriptsdir=./javascripts}/ASCIIMathML.js[]
+/*]]>*/
+</script>
+endif::linkcss[]
+endif::asciimath[]
+ifdef::latexmath[]
+ifdef::linkcss[]
+<script type="text/javascript" src="{scriptsdir=.}/LaTeXMathML.js"></script>
+endif::linkcss[]
+ifndef::linkcss[]
+<script type="text/javascript">
+# Escape as CDATA to pass validators.
+/*<![CDATA[*/
+include1::{scriptsdir=./javascripts}/LaTeXMathML.js[]
+/*]]>*/
+</script>
+endif::linkcss[]
+endif::latexmath[]
+{docinfo1,docinfo2#}{include:{docdir}/docinfo.html}
+{docinfo,docinfo2#}{include:{docdir}/{docname}-docinfo.html}
+</head>
+<body class="{doctype}"{max-width? style="max-width:{max-width}"}>
+# Article, book header.
+ifndef::doctype-manpage[]
+<div id="header">
+ifndef::notitle[<h1>{doctitle}</h1>]
+ifdef::doctitle[]
+<span id="author">{author}</span><br>
+<span id="email" class="monospaced">&lt;<a href="mailto:{email}">{email}</a>&gt;</span><br>
+<span id="revnumber">version {revnumber}{revdate?,}</span>
+<span id="revdate">{revdate}</span>
+<br><span id="revremark">{revremark}</span>
+endif::doctitle[]
+ifdef::toc,toc2[{template:toc}]
+</div>
+endif::doctype-manpage[]
+# Man page header.
+ifdef::doctype-manpage[]
+<div id="header">
+<h1>
+{doctitle} Manual Page
+</h1>
+ifdef::toc,toc2[{template:toc}]
+<h2>{manname-title}</h2>
+<div class="sectionbody">
+<p>{manname} -
+   {manpurpose}
+</p>
+</div>
+</div>
+endif::doctype-manpage[]
+<div id="content">
+
+[footer]
+</div>
+{disable-javascript%<div id="footnotes"><hr></div>}
+<div id="footer">
+<div id="footer-text">
+template::[footer-text]
+</div>
+ifdef::badges[]
+<div id="footer-badges">
+ifndef::icons[]
+Valid <a href="http://validator.w3.org/check?uri=referer">XHTML</a>
+and <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a>.
+endif::icons[]
+ifdef::icons[]
+<a href="http://validator.w3.org/check?uri=referer">
+  <img style="border:0;width:88px;height:31px"
+    src="http://www.w3.org/Icons/valid-xhtml11-blue"
+    alt="Valid XHTML 1.1" height="31" width="88">
+</a>
+<a href="http://jigsaw.w3.org/css-validator/">
+  <img style="border:0;width:88px;height:31px"
+    src="http://jigsaw.w3.org/css-validator/images/vcss-blue"
+    alt="Valid CSS!">
+</a>
+<a href="http://www.mozilla.org/products/firefox/">
+  <img style="border:none; width:110px; height:32px;"
+       src="http://www.spreadfirefox.com/community/images/affiliates/Buttons/110x32/safer.gif"
+       alt="Get Firefox!">
+</a>
+endif::icons[]
+</div>
+endif::badges[]
+</div>
+</body>
+</html>
+
+ifdef::doctype-manpage[]
+[synopsis]
+template::[sect1]
+endif::doctype-manpage[]
+
diff --git a/doc/www/javascripts/asciidoc.js b/doc/www/javascripts/asciidoc.js
new file mode 100644 (file)
index 0000000..2ad6c41
--- /dev/null
@@ -0,0 +1,189 @@
+var asciidoc = {  // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+  function getText(el) {
+    var text = "";
+    for (var i = el.firstChild; i != null; i = i.nextSibling) {
+      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+        text += i.data;
+      else if (i.firstChild != null)
+        text += getText(i);
+    }
+    return text;
+  }
+
+  function TocEntry(el, text, toclevel) {
+    this.element = el;
+    this.text = text;
+    this.toclevel = toclevel;
+  }
+
+  function tocEntries(el, toclevels) {
+    var result = new Array;
+    var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
+    // Function that scans the DOM tree for header elements (the DOM2
+    // nodeIterator API would be a better technique but not supported by all
+    // browsers).
+    var iterate = function (el) {
+      for (var i = el.firstChild; i != null; i = i.nextSibling) {
+        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+          var mo = re.exec(i.tagName);
+          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+          }
+          iterate(i);
+        }
+      }
+    }
+    iterate(el);
+    return result;
+  }
+
+  var toc = document.getElementById("toc");
+  if (!toc) {
+    return;
+  }
+
+  // Delete existing TOC entries in case we're reloading the TOC.
+  var tocEntriesToRemove = [];
+  var i;
+  for (i = 0; i < toc.childNodes.length; i++) {
+    var entry = toc.childNodes[i];
+    if (entry.nodeName == 'DIV'
+     && entry.getAttribute("class")
+     && entry.getAttribute("class").match(/^toclevel/))
+      tocEntriesToRemove.push(entry);
+  }
+  for (i = 0; i < tocEntriesToRemove.length; i++) {
+    toc.removeChild(tocEntriesToRemove[i]);
+  }
+  
+  // Rebuild TOC entries.
+  var entries = tocEntries(document.getElementById("content"), toclevels);
+  for (var i = 0; i < entries.length; ++i) {
+    var entry = entries[i];
+    if (entry.element.id == "")
+      entry.element.id = "_toc_" + i;
+    var a = document.createElement("a");
+    a.href = "#" + entry.element.id;
+    a.appendChild(document.createTextNode(entry.text));
+    var div = document.createElement("div");
+    div.appendChild(a);
+    div.className = "toclevel" + entry.toclevel;
+    toc.appendChild(div);
+  }
+  if (entries.length == 0)
+    toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+  // Delete existing footnote entries in case we're reloading the footnodes.
+  var i;
+  var noteholder = document.getElementById("footnotes");
+  if (!noteholder) {
+    return;
+  }
+  var entriesToRemove = [];
+  for (i = 0; i < noteholder.childNodes.length; i++) {
+    var entry = noteholder.childNodes[i];
+    if (entry.nodeName == 'DIV' && entry.getAttribute("class") == "footnote")
+      entriesToRemove.push(entry);
+  }
+  for (i = 0; i < entriesToRemove.length; i++) {
+    noteholder.removeChild(entriesToRemove[i]);
+  }
+
+  // Rebuild footnote entries.
+  var cont = document.getElementById("content");
+  var spans = cont.getElementsByTagName("span");
+  var refs = {};
+  var n = 0;
+  for (i=0; i<spans.length; i++) {
+    if (spans[i].className == "footnote") {
+      n++;
+      var note = spans[i].getAttribute("data-note");
+      if (!note) {
+        // Use [\s\S] in place of . so multi-line matches work.
+        // Because JavaScript has no s (dotall) regex flag.
+        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+        spans[i].innerHTML =
+          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+        spans[i].setAttribute("data-note", note);
+      }
+      noteholder.innerHTML +=
+        "<div class='footnote' id='_footnote_" + n + "'>" +
+        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+        n + "</a>. " + note + "</div>";
+      var id =spans[i].getAttribute("id");
+      if (id != null) refs["#"+id] = n;
+    }
+  }
+  if (n == 0)
+    noteholder.parentNode.removeChild(noteholder);
+  else {
+    // Process footnoterefs.
+    for (i=0; i<spans.length; i++) {
+      if (spans[i].className == "footnoteref") {
+        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+        href = href.match(/#.*/)[0];  // Because IE return full URL.
+        n = refs[href];
+        spans[i].innerHTML =
+          "[<a href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+      }
+    }
+  }
+},
+
+install: function(toclevels) {
+  var timerId;
+
+  function reinstall() {
+    asciidoc.footnotes();
+    if (toclevels) {
+      asciidoc.toc(toclevels);
+    }
+  }
+
+  function reinstallAndRemoveTimer() {
+    clearInterval(timerId);
+    reinstall();
+  }
+
+  timerId = setInterval(reinstall, 500);
+  if (document.addEventListener)
+    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+  else
+    window.onload = reinstallAndRemoveTimer;
+}
+
+}
diff --git a/doc/www/lang-en.conf b/doc/www/lang-en.conf
new file mode 100644 (file)
index 0000000..9d1c6d4
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# AsciiDoc English language configuration file.
+#
+
+[attributes]
+# Captions, used by (X)HTML backends.
+# Captions on RHS are displayed in outputs.
+ifdef::basebackend-html[]
+
+caution-caption=Caution
+important-caption=Important
+note-caption=Note
+tip-caption=Tip
+warning-caption=Warning
+figure-caption=Figure
+table-caption=Table
+example-caption=Example
+toc-title=Table of Contents
+appendix-caption=Appendix
+# Man page NAME section title.
+manname-title=NAME
+
+[footer-text]
+Version {revnumber}{basebackend-xhtml11?<br />}{basebackend-xhtml11=<br>}
+Last updated {docdate} {doctime}
+
+endif::basebackend-html[]
+
+
+[specialsections]
+# DocBook special sections.
+# The regular expression on LHS is matched against source titles.
+ifdef::basebackend-docbook[]
+
+ifdef::doctype-article[]
+^Abstract$=abstract
+endif::doctype-article[]
+
+ifdef::doctype-book[]
+^Colophon$=colophon
+^Dedication$=dedication
+^Preface$=preface
+endif::doctype-book[]
+
+^Index$=index
+^(Bibliography|References)$=bibliography
+^Glossary$=glossary
+^Appendix [A-Z][:.](?P<title>.*)$=appendix
+
+endif::basebackend-docbook[]
+
+ifdef::doctype-manpage[]
+(?i)^SYNOPSIS$=synopsis
+endif::doctype-manpage[]
diff --git a/doc/www/netatalk-relnotes.conf b/doc/www/netatalk-relnotes.conf
new file mode 100644 (file)
index 0000000..594ee2d
--- /dev/null
@@ -0,0 +1,285 @@
+#\r
+# netatalk.conf\r
+#\r
+# Asciidoc global configuration file.\r
+# css backend, generates XHTML 1.0 conformant markup.\r
+#\r
+# Included in css-embedded.conf\r
+#\r
+\r
+# Start with the html backend configuration.\r
+# include::html.conf[]\r
+\r
+[titles]\r
+underlines="--","==","~~","^^","++"\r
+\r
+[glossary]\r
+basebackend=css\r
+basebackend-css=\r
+basebackend-html\r
+dtddecl=PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"\r
+\r
+[tags]\r
+# Add title class.\r
+ilist={title?<p class="listtitle"><b>{title}</b></p>}<ul>|</ul>\r
+olist={title?<p class="listtitle"><b>{title}</b></p>}<ol>|</ol>\r
+vlist={title?<p class="listtitle"><b>{title}</b></p>}<dl>|</dl>\r
+qlist={title?<p class="listtitle"><b>{title}</b></p>}<ol>|</ol>\r
+\r
+[under-construction-blockmacro]\r
+<p class="under-construction">\r
+This page is currently under construction.<br/>\r
+Please return soon.\r
+</p>\r
+\r
+[image-inlinemacro]\r
+<a class="imagelink" href="{link}">\r
+# border="0" so broken IE6 does not put border round linked image.\r
+  <img src="{target}" alt="{1={target}}"{1? title="{1}"}{width? width="{width}"}{height? height="{height}"} border="0"/>\r
+{link#}</a>\r
+\r
+[image-blockmacro]\r
+<div class="image">\r
+  <p>{link?<a class="imagelink" href="{link}">}\r
+# border="0" so broken IE6 does not put border round linked image.\r
+    <img src="{target}" alt="{1={target}}"{1? title="{1}"}{width? width="{width}"}{height? height="{height}"} border="0"/>\r
+  {link?</a>}</p>\r
+  <p class="imagetitle"><b>Figure:</b> {title}</p>\r
+</div>\r
+\r
+# DEPRECATED.\r
+[graphic]\r
+<div class="graphic">\r
+  <p><img src="{target}" alt="{caption={target}}"/></p>\r
+  <p class="graphictitle"><b>Figure:</b> {title}</p>\r
+</div>\r
+\r
+# Paragraph substitution.\r
+[indentedparagraph]\r
+<p class="blocktitle"><b>Example:</b> {title}</p>\r
+#<div class="indentedparagraph"><pre>|</pre></div>\r
+&nbsp;&nbsp;&nbsp;<a href="|">|</a>\r
+\r
+# Delimited block substitution.\r
+[indentedblock]\r
+<p class="blocktitle"><b>Example:</b> {title}</p>\r
+<div class="indentedblock"><pre>\r
+|\r
+</pre></div>\r
+\r
+[verbatimblock]\r
+<p class="blocktitle"><b>Example:</b> {title}</p>\r
+<div class="verbatimblock"><pre>\r
+|\r
+</pre></div>\r
+\r
+[sidebarblock]\r
+<div class="sidebarblock">\r
+<p class="sidebartitle">{title}</p>\r
+|\r
+</div>\r
+\r
+[customblock]\r
+|\r
+\r
+[table]\r
+# Table captions not used because IE6 is broken.\r
+<p class="tabletitle"><b>Table:</b> {title}</p>\r
+# If you want styled table borders in IE use the following table tag:\r
+# 1. Border style specified here rather than in CSS because IE6 is broken.\r
+# 2. bordercolor attribute is IE specific and not valid XHTML 1.0.\r
+#<table rules="groups" border="2" bordercolor="green" frame="hsides"\r
+#      cellspacing="0" cellpadding="4">\r
+#\r
+# Use this in preference to be strictly XHTML 1.0 conformant.\r
+<table rules="groups" frame="{noborders?void}{noborders!hsides}" cellspacing="0" cellpadding="4">\r
+{headrows#}<thead{noborders? style="border-width: 0;"}>\r
+{headrows}\r
+{headrows#}</thead>\r
+{footrows#}<tfoot{noborders? style="border-width: 0;"}>\r
+{footrows}\r
+{footrows#}</tfoot>\r
+<tbody{noborders? style="border-width: 0;"}>\r
+{bodyrows}\r
+</tbody>\r
+</table>\r
+\r
+#-------------------------\r
+# article and book document types\r
+# Both use the article.css stylesheet\r
+#-------------------------\r
+ifndef::doctype-manpage[]\r
+\r
+[header]\r
+<!DOCTYPE html {dtddecl}>\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\r
+<meta name="description" content="Netatalk - Unix file and print services for Apple clients" />\r
+<meta name="keywords" content="Netatalk, AFP, AFP Server, File Server, PAP, Print Server, Appletalk, Mac, OSX, OS X, OS9, OS 9" />\r
+<meta name="language" content="EN" />\r
+<meta name="publisher" content="netatalk.sourceforge.net" />\r
+<meta name="robots" content="Follow" />\r
+<link rel="stylesheet" type="text/css" charset="iso-8859-1" href="/css/site.css" />\r
+<link rel="stylesheet" type="text/css" charset="iso-8859-1" href="/css/printer.css" media="print" />\r
+<link rel="alternate stylesheet" type="text/css" charset="iso-8859-1" href="/css/printer.css" title="Printer" />\r
+<link rel="copyright" title="GNU General Public License" href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt" />\r
+<link rel="author" title="The Netatalk Development Team" href="http://netatalk.sf.net" />\r
+<link rel="home" href="index.php" title="Netatalk Home" />\r
+<link rel="home" href="http://www.sourceforge.net/projects/netatalk" title="Netatalk Sourceforge" />\r
+<link rel="bookmark" href="http://sourceforge.net/project/showfiles.php?group_id=8642" title="Downloads" />\r
+\r
+<title>Netatalk Release Notes</title>\r
+</head>\r
+<body>\r
+<div id="header">\r
+<div id="logo"></div>\r
+<div id="menlinks">\r
+        <a href="/" title="Return to Netatalk home">[main]</a>\r
+        <a href="https://sourceforge.net/apps/mediawiki/netatalk/index.php?title=Main_Page" title="Netatalk Wiki">[wiki]</a>\r
+        <a href="/3.0/htmldocs" title="Netatalk Manual">[documentation]</a>\r
+        <a href="http://sourceforge.net/project/showfiles.php?group_id=8642" title="Download Netatalk from sourceforge">[downloads]</a>\r
+        <a href="/support.php" title="Support">[support]</a>\r
+        <a href="/links.php" title="Netatalk related links">[links]</a>\r
+        <img src="/gfx/end.gif" alt="" width="125" height="7" />\r
+</div>\r
+</div>\r
+<div id="header-print">\r
+<h1>netatalk.sourceforge.net</h1>\r
+</div>\r
+<div class="search">\r
+<h4> search netatalk.sf.net</h4>\r
+<form method="get" action="http://www.google.com/search">\r
+<p>\r
+<input type="text" name="q" size="10" maxlength="255" value="" />\r
+<input type="hidden" name="hl" value="de" />\r
+<input type="hidden" name="sitesearch" value="netatalk.sourceforge.net" />\r
+<input type="submit" name="btnG" value="Go" />\r
+</p>\r
+</form>\r
+<span class="italic">powered by Google</span>\r
+</div>\r
+<div id="content">\r
+<h1>{doctitle}</h1>\r
+\r
+[footer]\r
+</div>\r
+<div class="footer">\r
+<span class="italic">webspace sponsored by</span><br />\r
+<!-- use a table for now -->\r
+<table>\r
+<tr>\r
+<td><a href="http://www.sf.net"><img src="http://sourceforge.net/sflogo.php?group_id=8642&amp;type=1" style="border:0;width:88px;height:31px" width="88" height="31" alt="SourceForge.net Logo" /></a></td>\r
+<td><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></td>\r
+<td><a href="http://jigsaw.w3.org/css-validator/"><img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!" /></a></td>\r
+</tr>\r
+</table>\r
+</div>\r
+</body>\r
+</html>\r
+\r
+[preamble]\r
+# Untitled elements between header and first section title.\r
+<div id="body">\r
+|\r
+</div>\r
+\r
+[sect0]\r
+<h2 class="sect0">{1?<a name="{1}"></a>}{title}</h2>\r
+|\r
+\r
+[sect1]\r
+<h2>{1?<a name="{1}"></a>}{section-numbers?{sectnum} }{title}</h2>\r
+|\r
+\r
+[sect2]\r
+<h3>{1?<a name="{1}"></a>}{section-numbers?{sectnum} }{title}</h3>\r
+|\r
+\r
+[sect3]\r
+<h4>{1?<a name="{1}"></a>}{section-numbers?{sectnum} }{title}</h4>\r
+|\r
+\r
+[sect4]\r
+<h5>{1?<a name="{1}"></a>}{title}</h5>\r
+|\r
+\r
+endif::doctype-manpage[]\r
+\r
+#-------------------------\r
+# manpage document type\r
+#-------------------------\r
+ifdef::doctype-manpage[]\r
+\r
+[header]\r
+<!DOCTYPE html {dtddecl}>\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />\r
+<meta name="generator" content="AsciiDoc {asciidoc-version}" />\r
+<meta name="author" content="{author}" />\r
+<meta name="author-email" content="{email}" />\r
+<link rel="stylesheet" href="manpage.css" type="text/css" />\r
+<title>{mantitle}</title>\r
+</head>\r
+<body>\r
+<div id="content">\r
+<h1>{doctitle} Manual Page</h1>\r
+<h2>NAME</h2>\r
+<p>{manname} -\r
+   {manpurpose}\r
+</p>\r
+\r
+[footer]\r
+<div id="footer">\r
+<p>\r
+Version {revision}<br/>\r
+Last updated {localdate} {localtime}\r
+</p>\r
+<p><span class="ahem">This document might look funny (or very plain) to you, since you're not using a browser which (correctly) supports CSS.</span></p>\r
+<div id="badges">\r
+<table border="0" cellpadding="8" summary="Badges">\r
+<tr>\r
+<td><a href="http://validator.w3.org/check/referer"><img\r
+# Source badge locally.\r
+#src="http://www.w3.org/Icons/valid-xhtml10"\r
+src="valid-xhtml10.png"\r
+alt="Valid XHTML 1.0" height="31" width="88" /></a></td>\r
+\r
+<td><a href="http://jigsaw.w3.org/css-validator/"> <img border="0"\r
+# Source badge locally.\r
+#src="http://jigsaw.w3.org/css-validator/images/vcss"\r
+src="vcss.png"\r
+alt="Valid CSS" width="88" height="31" /></a></td>\r
+</tr>\r
+</table>\r
+</div>\r
+</div>\r
+</div>\r
+</body>\r
+</html>\r
+\r
+# Section macros\r
+[sect-synopsis]\r
+<div id="synopsis">\r
+<h2>SYNOPSIS</h2>\r
+|\r
+</div>\r
+\r
+[sect1]\r
+<h2>{1?<a name="{1}"></a>}{title}</h2>\r
+|\r
+\r
+[sect2]\r
+<h3>{1?<a name="{1}"></a>}{title}</h3>\r
+|\r
+\r
+[sect3]\r
+<h4>{1?<a name="{1}"></a>}{title}</h4>\r
+|\r
+\r
+[sect4]\r
+<h5>{1?<a name="{1}"></a>}{title}</h5>\r
+|\r
+\r
+endif::doctype-manpage[]\r
diff --git a/doc/www/stylesheets/asciidoc.css b/doc/www/stylesheets/asciidoc.css
new file mode 100644 (file)
index 0000000..1475be7
--- /dev/null
@@ -0,0 +1,508 @@
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+  font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+  font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+  margin: 1em 5% 1em 5%;
+}
+
+a {
+  color: blue;
+  text-decoration: underline;
+}
+a:visited {
+  color: fuchsia;
+}
+
+em {
+  font-style: italic;
+  color: navy;
+}
+
+strong {
+  font-weight: bold;
+  color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  color: #527bbd;
+  margin-top: 1.2em;
+  margin-bottom: 0.5em;
+  line-height: 1.3;
+}
+
+h1, h2, h3 {
+  border-bottom: 2px solid silver;
+}
+h2 {
+  padding-top: 0.5em;
+}
+h3 {
+  float: left;
+}
+h3 + * {
+  clear: left;
+}
+h5 {
+  font-size: 1.0em;
+}
+
+div.sectionbody {
+  margin-left: 0;
+}
+
+hr {
+  border: 1px solid silver;
+}
+
+p {
+  margin-top: 0.5em;
+  margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+  margin-top: 0;
+}
+ul > li     { color: #aaa; }
+ul > li > * { color: black; }
+
+pre {
+  padding: 0;
+  margin: 0;
+}
+
+#author {
+  color: #527bbd;
+  font-weight: bold;
+  font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+  font-size: small;
+  border-top: 2px solid silver;
+  padding-top: 0.5em;
+  margin-top: 4.0em;
+}
+#footer-text {
+  float: left;
+  padding-bottom: 0.5em;
+}
+#footer-badges {
+  float: right;
+  padding-bottom: 0.5em;
+}
+
+#preamble {
+  margin-top: 1.5em;
+  margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.admonitionblock {
+  margin-top: 2.0em;
+  margin-bottom: 2.0em;
+  margin-right: 10%;
+  color: #606060;
+}
+
+div.content { /* Block element content. */
+  padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+  color: #527bbd;
+  font-weight: bold;
+  text-align: left;
+  margin-top: 1.0em;
+  margin-bottom: 0.5em;
+}
+div.title + * {
+  margin-top: 0;
+}
+
+td div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content + div.title {
+  margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+  background: #ffffee;
+  border: 1px solid #dddddd;
+  border-left: 4px solid #f0f0f0;
+  padding: 0.5em;
+}
+
+div.listingblock > div.content {
+  border: 1px solid #dddddd;
+  border-left: 5px solid #f0f0f0;
+  background: #f8f8f8;
+  padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+  padding-left: 1.0em;
+  margin-left: 1.0em;
+  margin-right: 10%;
+  border-left: 5px solid #f0f0f0;
+  color: #777777;
+}
+
+div.quoteblock > div.attribution {
+  padding-top: 0.5em;
+  text-align: right;
+}
+
+div.verseblock > pre.content {
+  font-family: inherit;
+  font-size: inherit;
+}
+div.verseblock > div.attribution {
+  padding-top: 0.75em;
+  text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+  text-align: left;
+}
+
+div.admonitionblock .icon {
+  vertical-align: top;
+  font-size: 1.1em;
+  font-weight: bold;
+  text-decoration: underline;
+  color: #527bbd;
+  padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+  padding-left: 0.5em;
+  border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+  border-left: 3px solid #dddddd;
+  padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+dt {
+  margin-top: 0.5em;
+  margin-bottom: 0;
+  font-style: normal;
+  color: navy;
+}
+dd > *:first-child {
+  margin-top: 0.1em;
+}
+
+ul, ol {
+    list-style-position: outside;
+}
+ol.arabic {
+  list-style-type: decimal;
+}
+ol.loweralpha {
+  list-style-type: lower-alpha;
+}
+ol.upperalpha {
+  list-style-type: upper-alpha;
+}
+ol.lowerroman {
+  list-style-type: lower-roman;
+}
+ol.upperroman {
+  list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+  margin-top: 0.1em;
+  margin-bottom: 0.1em;
+}
+
+tfoot {
+  font-weight: bold;
+}
+td > div.verse {
+  white-space: pre;
+}
+
+div.hdlist {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+div.hdlist tr {
+  padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+  font-weight: bold;
+}
+td.hdlist1 {
+  vertical-align: top;
+  font-style: normal;
+  padding-right: 0.8em;
+  color: navy;
+}
+td.hdlist2 {
+  vertical-align: top;
+}
+div.hdlist.compact tr {
+  margin: 0;
+  padding-bottom: 0;
+}
+
+.comment {
+  background: yellow;
+}
+
+.footnote, .footnoteref {
+  font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+  vertical-align: super;
+}
+
+#footnotes {
+  margin: 20px 0 20px 0;
+  padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+  margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+  border: none;
+  border-top: 1px solid silver;
+  height: 1px;
+  text-align: left;
+  margin-left: 0;
+  width: 20%;
+  min-width: 100px;
+}
+
+div.colist td {
+  padding-right: 0.5em;
+  padding-bottom: 0.3em;
+  vertical-align: top;
+}
+div.colist td img {
+  margin-top: 0.3em;
+}
+
+@media print {
+  #footer-badges { display: none; }
+}
+
+#toc {
+  margin-bottom: 2.5em;
+}
+
+#toctitle {
+  color: #527bbd;
+  font-size: 1.1em;
+  font-weight: bold;
+  margin-top: 1.0em;
+  margin-bottom: 0.1em;
+}
+
+div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+div.toclevel2 {
+  margin-left: 2em;
+  font-size: 0.9em;
+}
+div.toclevel3 {
+  margin-left: 4em;
+  font-size: 0.9em;
+}
+div.toclevel4 {
+  margin-left: 6em;
+  font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+tt {
+  font-family: monospace;
+  font-size: inherit;
+  color: navy;
+}
+
+div.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.tableblock > table {
+  border: 3px solid #527bbd;
+}
+thead, p.table.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.table {
+  margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+  border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+  border-left-style: none;
+  border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+  border-top-style: none;
+  border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+.monospaced {
+  font-family: monospace;
+  font-size: inherit;
+  color: navy;
+}
+
+table.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.tableblock {
+  margin-top: 0;
+}
+table.tableblock {
+  border-width: 3px;
+  border-spacing: 0px;
+  border-style: solid;
+  border-color: #527bbd;
+  border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+  border-width: 1px;
+  padding: 4px;
+  border-style: solid;
+  border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+  border-left-style: hidden;
+  border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+  border-top-style: hidden;
+  border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+  border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+  text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+  text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+  text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+  vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+  vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+  vertical-align: bottom;
+}
index ad24d2bbce4f7182171bf3437ad08da84f421696..e5e309fffbd306b8cf7f6398f148b8d398c87723 100644 (file)
@@ -1,5 +1,44 @@
 dnl Kitchen sink for configuration macros
 
+dnl Check for docbook
+AC_DEFUN(AX_CHECK_DOCBOOK, [
+  # It's just rude to go over the net to build
+  XSLTPROC_FLAGS=--nonet
+  DOCBOOK_ROOT=
+
+  AC_ARG_WITH(docbook,
+    AS_HELP_STRING(
+      [--with-docbook],
+      [Path to Docbook XSL directory]
+    ),
+    [DOCBOOK_ROOT=$withval]
+  )
+
+  if test -n "$DOCBOOK_ROOT" ; then
+    AC_CHECK_PROG(XSLTPROC,xsltproc,xsltproc,)
+    XSLTPROC_WORKS=no
+    if test -n "$XSLTPROC"; then
+      AC_MSG_CHECKING([whether xsltproc works])
+      DB_FILE="$DOCBOOK_ROOT/html/docbook.xsl"
+      $XSLTPROC $XSLTPROC_FLAGS $DB_FILE >/dev/null 2&>&1 << END
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+<book id="test">
+</book>
+END
+      if test "$?" = 0; then
+        XSLTPROC_WORKS=yes
+      fi
+      AC_MSG_RESULT($XSLTPROC_WORKS)
+    fi
+  fi
+
+  AM_CONDITIONAL(HAVE_XSLTPROC, test x"$XSLTPROC_WORKS" = x"yes")
+  AC_SUBST(XSLTPROC_FLAGS)
+  AC_SUBST(DOCBOOK_ROOT)
+  AC_SUBST(XSLTPROC)
+])
+
 dnl Check for dtrace
 AC_DEFUN([AC_NETATALK_DTRACE], [
   AC_ARG_WITH(dtrace,
index 20b143643467aa181fb2bcb268e5e49881aa35e2..0e51d12885dbd44a37cea70ed0911eff817f9fd4 100644 (file)
@@ -3,11 +3,11 @@
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
 .\"      Date: 02 Sep 2011
-.\"    Manual: Netatalk 3.0
-.\"    Source: Netatalk 3.0
+.\"    Manual: Netatalk 3.0.4dev
+.\"    Source: Netatalk 3.0.4dev
 .\"  Language: English
 .\"
-.TH "AD" "1" "02 Sep 2011" "Netatalk 3.0" "Netatalk 3.0"
+.TH "AD" "1" "02 Sep 2011" "Netatalk 3.0.4dev" "Netatalk 3.0.4dev"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------